mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-16 18:24:36 +00:00
Merge pull request #586 from bwssytems/SecurityImpl
Merge security impl branch BridgeSettings.configWriter needs synchonized question Fixes #571 [feature request] Web Users/Login enhancement Fixes #402 User authentication... question Fixes #270 Security VS habridge enhancement question Fixes #390 issue tcp command bug Fixes #564 Device inactive not working bug Fixes #565 opened 13 days ago
This commit is contained in:
36
README.md
36
README.md
@@ -59,23 +59,23 @@ ATTENTION: This requires JDK 1.8 to run
|
||||
ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below.
|
||||
|
||||
```
|
||||
java -jar ha-bridge-4.3.1.jar
|
||||
java -jar ha-bridge-4.5.0.jar
|
||||
```
|
||||
### Automation on Linux systems
|
||||
To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge
|
||||
|
||||
Create the directory and make sure that ha-bridge-4.3.1.jar is in your /home/pi/habridge directory.
|
||||
Create the directory and make sure that ha-bridge-4.5.0.jar is in your /home/pi/habridge directory.
|
||||
```
|
||||
pi@raspberrypi:~ $ mkdir habridge
|
||||
pi@raspberrypi:~ $ cd habridge
|
||||
|
||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.3.1/ha-bridge-4.3.1.jar
|
||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.5.0/ha-bridge-4.5.0.jar
|
||||
```
|
||||
Create the directory and make sure that ha-bridge-4.3.1.jar is in your /home/pi/habridge directory.
|
||||
Create the directory and make sure that ha-bridge-4.5.0.jar is in your /home/pi/habridge directory.
|
||||
```
|
||||
pi@raspberrypi:~ $ mkdir habridge
|
||||
pi@raspberrypi:~ $ cd habridge
|
||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.3.1/ha-bridge-4.3.1.jar
|
||||
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.5.0/ha-bridge-4.5.0.jar
|
||||
```
|
||||
#### System Control Setup on a pi (preferred)
|
||||
For next gen Linux systems (this includes the Raspberry Pi), here is a systemctl unit file that you can install. Here is a link on how to do this: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
|
||||
@@ -94,8 +94,8 @@ After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.3.1.jar
|
||||
WorkingDirectory=/home/pi/habridge
|
||||
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.0.jar
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -130,7 +130,7 @@ Then cut and past this, modify any locations that are not correct
|
||||
```
|
||||
cd /home/pi/habridge
|
||||
rm /home/pi/habridge/habridge-log.txt
|
||||
nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.3.1.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
|
||||
nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
|
||||
|
||||
chmod 777 /home/pi/habridge/habridge-log.txt
|
||||
```
|
||||
@@ -213,6 +213,16 @@ The default ip address for the bridge to listen on is all interfaces (0.0.0.0).
|
||||
```
|
||||
java -jar -Dserver.ip=192.168.1.1 ha-bridge-W.X.Y.jar
|
||||
```
|
||||
### -Dsecurity.key=`<Your Key To Encrypt Security Data>`
|
||||
This option is very important to set if you will be using username/passwords to secure the ha-bridge. The ha-bridge needs to encrypt the settings in the config file and to make sure they are secured specifically to you is to provide this key. Otherwise a default key is used and it is available in the code on github for the ha-bridge here, so not very secure in that sense. **It is very important provide this if you are using username/password.** To override the default, specify -Dsecurity.key=`<Your Key To Encrypt Security Data>` explicitly on the command line. This is will prevent any issues if your config file gets hacked. The command line example:
|
||||
```
|
||||
java -jar -Dsecurity.key=Xfawer354WertSdf321234asd ha-bridge-W.X.Y.jar
|
||||
```
|
||||
### -Dexec.garden=`<The path to your scripts and program directory>`
|
||||
This sets a directory of your choosing to have a walled area for what can be executed by the Exec Command type. This is a good feature to use if you use the capabilities of executing a script or program from the ha-bridge. The default is not set which allows any program or script to be called and anyone with access to the your system could create an exec command call and execute it from the api. This is will prevent any issues if your system gets hacked. To override the default, specify -Dexec.garden=`<The path to your scripts and program directory>` explicitly on the command line. The command line example:
|
||||
```
|
||||
java -jar -Dexec.garden=C:\Users\John\bin
|
||||
```
|
||||
## HA Bridge Usage and Configuration
|
||||
This section will cover the basics of configuration and where this configuration can be done. This requires that you have started your bridge process and then have pointed your
|
||||
favorite web interface by going to the http://<my ip address>:<port> or http://localhost:<port> with port you have assigned. The default quick link is http://localhost for your reference.
|
||||
@@ -220,12 +230,18 @@ favorite web interface by going to the http://<my ip address>:<port> or http://l
|
||||
This screen allows you to see your devices you have configured for the ha-bridge to present to a controller, such as an Amazon Echo/Dot. It gives you a count of devices as there have been reports that the Echo only supports a limited number, but has been growing as of late, YMMV. You can test each device from this page as this calls the ha-bridge just as a controller would, i.e. the Echo. This is useful to make sure your configuration for each device is correct and for trouble shooting. You can also manages your devices as well by editing and making a new device copy as well as deleting it.
|
||||
|
||||
At the bottom of the screen is the "Bridge Device DB Backup" which can be accessed with clicking on the `+` to expand this frame. Here you can backup and restore configurations that you have saved. These configs can be named or by clicking the `Backup Device DB' button will create a backup and name it for you. You can manage these backups by restoring them or deleting them.
|
||||
#### Renumber Devices
|
||||
This changes the numbering of the added devices to start at 1 and goes up from there. It was originally intended for a conversion from the previous system version that used large numbers and was not necessary. This also allows the system to try and number sequentially. If you use this button, you will need to re-discover your devices as their ID's will have changed.
|
||||
#### Link
|
||||
If this is present, you have enabled the ue link button feature for the ha-bridge. If you want a new system to recognize the ha-bridge, you will need to press this button when you are doign a discovery.
|
||||
### The Bridge Control Tab
|
||||
This is where all of the configuration occurs for what ports and IP's the bridge runs on. It also contains the configurations for target devices so that Helper Tabs for configuration can be added as well as the connection information to control those devices.
|
||||
#### Bridge server
|
||||
This field is used to test the bridge server with the UPNP IP Address and to make sure that the bridge is responding.
|
||||
#### Bridge Control Buttons
|
||||
These buttons are for managing the bridge. The Save button is enabled when there is a change to the configuration. The Bridge Reinitialize button will recycle the internal running of the bridge in the java process. The Stop button will stop the java process. The Refresh button will refresh the page and settings.
|
||||
#### The Security Dialog
|
||||
This is where you can set the different security settings for the ha-bridge. There are two settings, one for enabling Hue like operation to secure the Hue api with the internally generated user for the calls that are done after the link button. The other is to secure the hue api with a username/password that is created as well. The other fields are to add and delete users and to set and change passwords for those users. If there are no users in the system, the system will not require a username/password to operate.
|
||||
#### Configuration Path and File
|
||||
The default location for the configuration file to contain the settings for the bridge is the relative path from where the bridge is started in "data/habridge.config". If you would like a different filename or directory, specify `<directory>/<filename>` explicitly.
|
||||
#### Device DB Path and File
|
||||
@@ -307,7 +323,9 @@ Example from device.db:
|
||||
[{"item":<a String that is quoted or another JSON object>,"type":"<atype>"."count":X."delay":X."filterIPs":"<comma separated list of IP addresses that are valid>"."httpVerb":"<GET,PUT,POST>","httpBody":"<body info>","httpHeaders":[{"name":"header name","value":"header value"},{"name":"another header","value":"another value"}],"contentType":"<http content type i.e application/json>"},{"item":<another item>,"type":"<aType>"}]
|
||||
```
|
||||
|
||||
The Add/Edit tab will show you the fields to fill in for the above in a form, when you hcae completed putting in the things you want, make sure to hit the `Add` button at the right.
|
||||
The format of the example is in JSON where the JSON tags equate to the UI labels of the On Items/Dim Items/Off Items. i.e.: JSON item = UI Target Item, JSON type = UI Type, etc...
|
||||
|
||||
The Add/Edit tab will show you the fields to fill in for the above in a form, when you have completed putting in the things you want, make sure to hit the `Add` button at the right.
|
||||
|
||||
The format of the item can be the default HTTP request which executes the URLs formatted as `http://<your stuff here>` as a GET. Other options to this are to select the HTTP Verb and add the data type and add a body that is passed with the request. Secure https is supported as well, just use `https://<your secure call here>`. When using POST and PUT, you have the ability to specify the body that will be sent with the request as well as the application type for the http call.
|
||||
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<version>4.5.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.bwssystems.HABridge;
|
||||
public class BridgeControlDescriptor {
|
||||
private boolean reinit;
|
||||
private boolean stop;
|
||||
private boolean linkButton;
|
||||
|
||||
public BridgeControlDescriptor() {
|
||||
super();
|
||||
@@ -22,4 +23,12 @@ public class BridgeControlDescriptor {
|
||||
public void setStop(boolean stop) {
|
||||
this.stop = stop;
|
||||
}
|
||||
|
||||
public boolean isLinkButton() {
|
||||
return linkButton;
|
||||
}
|
||||
|
||||
public void setLinkButton(boolean linkButton) {
|
||||
this.linkButton = linkButton;
|
||||
}
|
||||
}
|
||||
|
||||
356
src/main/java/com/bwssystems/HABridge/BridgeSecurity.java
Normal file
356
src/main/java/com/bwssystems/HABridge/BridgeSecurity.java
Normal file
@@ -0,0 +1,356 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.UUID;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.PBEParameterSpec;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.api.hue.HueError;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import spark.Request;
|
||||
|
||||
public class BridgeSecurity {
|
||||
private static final Logger log = LoggerFactory.getLogger(BridgeSecurity.class);
|
||||
private static final String USER_SESSION_ID = "user";
|
||||
private static final String DEPRACATED_INTERNAL_USER = "thehabridgeuser";
|
||||
private static final String TEST_USER_TYPE = "test_ha_bridge";
|
||||
private static final byte[] SALT = {
|
||||
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||
};
|
||||
private char[] habridgeKey;
|
||||
private String execGarden;
|
||||
private BridgeSecurityDescriptor securityDescriptor;
|
||||
private boolean settingsChanged;
|
||||
|
||||
public BridgeSecurity(char[] theKey, String theExecGarden) {
|
||||
habridgeKey = theKey;
|
||||
execGarden = theExecGarden;
|
||||
securityDescriptor = null;
|
||||
settingsChanged = false;
|
||||
}
|
||||
|
||||
public void setSecurityData(String theData) {
|
||||
String anError = null;
|
||||
if(theData != null && !theData.isEmpty()) {
|
||||
try {
|
||||
securityDescriptor = new Gson().fromJson(decrypt(theData), BridgeSecurityDescriptor.class);
|
||||
} catch (JsonSyntaxException e) {
|
||||
anError = e.getMessage();
|
||||
} catch (GeneralSecurityException e) {
|
||||
anError = e.getMessage();
|
||||
} catch (IOException e) {
|
||||
anError = e.getMessage();
|
||||
}
|
||||
if(anError != null)
|
||||
log.warn("Cound not get security data, using default security (none): " + anError);
|
||||
}
|
||||
|
||||
if(theData == null || anError != null) {
|
||||
securityDescriptor = new BridgeSecurityDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
public String getSecurityDescriptorData() throws UnsupportedEncodingException, GeneralSecurityException {
|
||||
return encrypt(new Gson().toJson(securityDescriptor));
|
||||
}
|
||||
|
||||
public boolean isUseLinkButton() {
|
||||
return securityDescriptor.isUseLinkButton();
|
||||
}
|
||||
|
||||
public String setPassword(User aUser) throws IOException {
|
||||
String error = null;
|
||||
if(aUser != null) {
|
||||
error = aUser.validate();
|
||||
if(error == null) {
|
||||
if(securityDescriptor.getUsers() != null) {
|
||||
User theUser = securityDescriptor.getUsers().get(aUser.getUsername());
|
||||
if(theUser != null) {
|
||||
theUser.setPassword(aUser.getPassword());
|
||||
theUser.setPassword2(null);
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
error = "User not found";
|
||||
}
|
||||
else
|
||||
error = "User not found";
|
||||
}
|
||||
}
|
||||
else
|
||||
error = "invalid user object given";
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
public String addUser(User aUser) throws IOException {
|
||||
String error = null;
|
||||
if(aUser != null) {
|
||||
error = aUser.validate();
|
||||
if(error == null) {
|
||||
if(securityDescriptor.getUsers() == null)
|
||||
securityDescriptor.setUsers(new HashMap<String, User>());
|
||||
if(securityDescriptor.getUsers().get(aUser.getUsername()) == null) {
|
||||
securityDescriptor.getUsers().put(aUser.getUsername(), aUser);
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
error = "Invalid request";
|
||||
}
|
||||
}
|
||||
else
|
||||
error = "invalid user object given";
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
public String delUser(User aUser) throws IOException {
|
||||
String error = null;
|
||||
if(aUser != null) {
|
||||
if(securityDescriptor.getUsers() != null) {
|
||||
if(securityDescriptor.getUsers().get(aUser.getUsername()) != null) {
|
||||
securityDescriptor.getUsers().remove(aUser.getUsername());
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
error = "User not found";
|
||||
}
|
||||
}
|
||||
else
|
||||
error = "invalid user object given";
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
public String getExecGarden() {
|
||||
return execGarden;
|
||||
}
|
||||
public void setUseLinkButton(boolean useThis) {
|
||||
securityDescriptor.setUseLinkButton(useThis);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
public boolean isSecureHueApi() {
|
||||
return securityDescriptor.isSecureHueApi();
|
||||
}
|
||||
|
||||
public void setSecureHueApi(boolean theState) {
|
||||
securityDescriptor.setSecureHueApi(theState);
|
||||
}
|
||||
public SecurityInfo getSecurityInfo() {
|
||||
SecurityInfo theInfo = new SecurityInfo();
|
||||
theInfo.setUseLinkButton(isUseLinkButton());
|
||||
theInfo.setSecureHueApi(isSecureHueApi());
|
||||
theInfo.setSecure(isSecure());
|
||||
return theInfo;
|
||||
}
|
||||
public LoginResult validatePassword(User targetUser) throws IOException {
|
||||
LoginResult result = new LoginResult();
|
||||
if(targetUser != null && targetUser.getUsername() != null) {
|
||||
if(securityDescriptor.getUsers() != null && securityDescriptor.getUsers().get(targetUser.getUsername()) != null) {
|
||||
User theUser = securityDescriptor.getUsers().get(targetUser.getUsername());
|
||||
if(theUser.getPassword() != null) {
|
||||
theUser.setPassword2(targetUser.getPassword());
|
||||
if(theUser.validatePassword()) {
|
||||
theUser.setPassword2(null);
|
||||
result.setUser(targetUser);
|
||||
}
|
||||
else
|
||||
result.setError("user or password not correct");
|
||||
} else {
|
||||
result.setError("input password is not set....");
|
||||
}
|
||||
}
|
||||
else
|
||||
result.setError("user or password not correct");
|
||||
}
|
||||
else
|
||||
result.setError("input user not given");
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isSecure() {
|
||||
return securityDescriptor.isSecure();
|
||||
}
|
||||
|
||||
public boolean isSettingsChanged() {
|
||||
return settingsChanged;
|
||||
}
|
||||
|
||||
public void setSettingsChanged(boolean settingsChanged) {
|
||||
this.settingsChanged = settingsChanged;
|
||||
}
|
||||
|
||||
public HueError[] validateWhitelistUser(String aUser, String userDescription, boolean strict) {
|
||||
String validUser = null;
|
||||
boolean found = false;
|
||||
if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null")
|
||||
&& !aUser.equalsIgnoreCase("")) {
|
||||
if (securityDescriptor.getWhitelist() != null) {
|
||||
Set<String> theUserIds = securityDescriptor.getWhitelist().keySet();
|
||||
Iterator<String> userIterator = theUserIds.iterator();
|
||||
while (userIterator.hasNext()) {
|
||||
validUser = userIterator.next();
|
||||
if (validUser.equals(aUser))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!found && !strict) {
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return HueErrorResponse.createResponse("1", "/api/" + aUser, "unauthorized user", null, null, null).getTheErrors();
|
||||
}
|
||||
|
||||
Object anUser = securityDescriptor.getWhitelist().remove(DEPRACATED_INTERNAL_USER);
|
||||
if(anUser != null)
|
||||
setSettingsChanged(true);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void newWhitelistUser(String aUser, String userDescription) {
|
||||
if(aUser.equals(DEPRACATED_INTERNAL_USER))
|
||||
return;
|
||||
if (securityDescriptor.getWhitelist() == null) {
|
||||
securityDescriptor.setWhitelist(new HashMap<>());
|
||||
}
|
||||
if(userDescription == null)
|
||||
userDescription = "auto insert user";
|
||||
|
||||
securityDescriptor.getWhitelist().put(aUser, WhitelistEntry.createEntry(userDescription));
|
||||
setSettingsChanged(true);
|
||||
}
|
||||
|
||||
public String createWhitelistUser(String userDescription) {
|
||||
String aUser = getNewUserID();
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
return aUser;
|
||||
}
|
||||
|
||||
public void convertWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||
securityDescriptor.setWhitelist(whitelist);
|
||||
}
|
||||
|
||||
private String getNewUserID() {
|
||||
UUID uid = UUID.randomUUID();
|
||||
StringTokenizer st = new StringTokenizer(uid.toString(), "-");
|
||||
String newUser = "";
|
||||
while (st.hasMoreTokens()) {
|
||||
newUser = newUser + st.nextToken();
|
||||
}
|
||||
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public void removeTestUsers() {
|
||||
if (securityDescriptor.getWhitelist() != null) {
|
||||
Object anUser = securityDescriptor.getWhitelist().remove(DEPRACATED_INTERNAL_USER);
|
||||
if(anUser != null)
|
||||
setSettingsChanged(true);
|
||||
|
||||
Iterator<Entry<String, WhitelistEntry>> it = securityDescriptor.getWhitelist().entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, WhitelistEntry> pair = it.next();
|
||||
it.remove(); // avoids a ConcurrentModificationException
|
||||
if(pair.getValue().getName().equals(TEST_USER_TYPE)) {
|
||||
securityDescriptor.getWhitelist().remove(pair.getKey());
|
||||
setSettingsChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException {
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
|
||||
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(habridgeKey));
|
||||
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
|
||||
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
|
||||
return base64Encode(pbeCipher.doFinal(property.getBytes("UTF-8")));
|
||||
}
|
||||
|
||||
private static String base64Encode(byte[] bytes) {
|
||||
return Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
|
||||
private String decrypt(String property) throws GeneralSecurityException, IOException {
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
|
||||
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(habridgeKey));
|
||||
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
|
||||
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
|
||||
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
|
||||
}
|
||||
|
||||
private static byte[] base64Decode(String property) throws IOException {
|
||||
return Base64.getDecoder().decode(property);
|
||||
}
|
||||
|
||||
public void addAuthenticatedUser(Request request, User u) {
|
||||
request.session().attribute(USER_SESSION_ID, u);
|
||||
|
||||
}
|
||||
|
||||
public void removeAuthenticatedUser(Request request) {
|
||||
request.session().removeAttribute(USER_SESSION_ID);
|
||||
|
||||
}
|
||||
|
||||
public User getAuthenticatedUser(Request request) {
|
||||
User theUser = request.session().attribute(USER_SESSION_ID);
|
||||
if(theUser == null) {
|
||||
String authHeader = request.headers("Authorization");
|
||||
if(authHeader != null) {
|
||||
byte[] authData;
|
||||
try {
|
||||
authData = base64Decode(authHeader.substring(6));
|
||||
} catch (IOException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
return theUser;
|
||||
}
|
||||
String[] credentials = new String(authData).split(":");
|
||||
String username = credentials[0];
|
||||
String password = credentials[1];
|
||||
theUser = new User();
|
||||
theUser.setUsername(username);
|
||||
theUser.setPassword(password);
|
||||
LoginResult theResult = null;
|
||||
try {
|
||||
theResult = validatePassword(theUser);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
return null;
|
||||
}
|
||||
if(theResult != null && theResult.getError() == null) {
|
||||
addAuthenticatedUser(request, theUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
return theUser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.util.Map;
|
||||
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||
|
||||
public class BridgeSecurityDescriptor {
|
||||
private Map<String, User> users;
|
||||
private boolean useLinkButton;
|
||||
private String execGarden;
|
||||
private boolean secureHueApi;
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
|
||||
public BridgeSecurityDescriptor() {
|
||||
super();
|
||||
this.setUseLinkButton(false);
|
||||
}
|
||||
|
||||
public Map<String, User> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(Map<String, User> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public boolean isUseLinkButton() {
|
||||
return useLinkButton;
|
||||
}
|
||||
|
||||
public void setUseLinkButton(boolean useLinkButton) {
|
||||
this.useLinkButton = useLinkButton;
|
||||
}
|
||||
|
||||
public String getExecGarden() {
|
||||
return execGarden;
|
||||
}
|
||||
|
||||
public void setExecGarden(String execGarden) {
|
||||
this.execGarden = execGarden;
|
||||
}
|
||||
|
||||
public boolean isSecureHueApi() {
|
||||
return secureHueApi;
|
||||
}
|
||||
|
||||
public void setSecureHueApi(boolean secureHueApi) {
|
||||
this.secureHueApi = secureHueApi;
|
||||
}
|
||||
public Map<String, WhitelistEntry> getWhitelist() {
|
||||
return whitelist;
|
||||
}
|
||||
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||
this.whitelist = whitelist;
|
||||
}
|
||||
|
||||
public boolean isSecure() {
|
||||
boolean secureFlag = false;
|
||||
if(users != null && !users.isEmpty()) {
|
||||
for (Map.Entry<String, User> entry : users.entrySet())
|
||||
{
|
||||
if(entry.getValue().getPassword() != null && !entry.getValue().getPassword().isEmpty()) {
|
||||
secureFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return secureFlag;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
@@ -10,6 +11,9 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -26,12 +30,20 @@ public class BridgeSettings extends BackupHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||
private BridgeSettingsDescriptor theBridgeSettings;
|
||||
private BridgeControlDescriptor bridgeControl;
|
||||
private BridgeSecurity bridgeSecurity;
|
||||
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
|
||||
|
||||
public BridgeSettings() {
|
||||
super();
|
||||
bridgeControl = new BridgeControlDescriptor();
|
||||
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||
String ipV6Stack = System.getProperty("ipV6Stack");
|
||||
bridgeSecurity = null;
|
||||
String theKey = System.getProperty("security.key");
|
||||
if(theKey == null)
|
||||
theKey = "IWantMyPasswordsToBeAbleToBeDecodedPleaseSeeTheReadme";
|
||||
String execGarden = System.getProperty("exec.garden");
|
||||
bridgeSecurity = new BridgeSecurity(theKey.toCharArray(), execGarden);
|
||||
String ipV6Stack = System.getProperty("ipV6Stack");
|
||||
if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) {
|
||||
System.setProperty("java.net.preferIPv4Stack" , "true");
|
||||
}
|
||||
@@ -43,6 +55,13 @@ public class BridgeSettings extends BackupHandler {
|
||||
public BridgeSettingsDescriptor getBridgeSettingsDescriptor() {
|
||||
return theBridgeSettings;
|
||||
}
|
||||
public BridgeSecurity getBridgeSecurity() {
|
||||
return bridgeSecurity;
|
||||
}
|
||||
public static String getCurrentDate() {
|
||||
return dateFormat.format(new Date());
|
||||
}
|
||||
|
||||
public void buildSettings() {
|
||||
String addressString = null;
|
||||
String theVeraAddress = null;
|
||||
@@ -128,7 +147,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setNestpwd(System.getProperty("nest.pwd"));
|
||||
}
|
||||
|
||||
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().equals("")) {
|
||||
if(theBridgeSettings.getUpnpConfigAddress() == null || theBridgeSettings.getUpnpConfigAddress().trim().equals("") || theBridgeSettings.getUpnpConfigAddress().trim().equals("0.0.0.0")) {
|
||||
addressString = checkIpAddress(null, true);
|
||||
if(addressString != null) {
|
||||
theBridgeSettings.setUpnpConfigAddress(addressString);
|
||||
@@ -174,7 +193,12 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setWebaddress(serverIpOverride);
|
||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||
|
||||
setupInternalTestUser();
|
||||
bridgeSecurity.setSecurityData(theBridgeSettings.getSecurityData());
|
||||
if(theBridgeSettings.getWhitelist() != null) {
|
||||
bridgeSecurity.convertWhitelist(theBridgeSettings.getWhitelist());
|
||||
theBridgeSettings.removeWhitelist();
|
||||
updateConfigFile();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadConfig() {
|
||||
@@ -203,6 +227,18 @@ public class BridgeSettings extends BackupHandler {
|
||||
log.debug("Save HA Bridge settings.");
|
||||
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
||||
JsonTransformer aRenderer = new JsonTransformer();
|
||||
if(bridgeSecurity.isSettingsChanged()) {
|
||||
try {
|
||||
newBridgeSettings.setSecurityData(bridgeSecurity.getSecurityDescriptorData());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.warn("could not get encoded security data: " + e.getMessage());
|
||||
return;
|
||||
} catch (GeneralSecurityException e) {
|
||||
log.warn("could not get encoded security data: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
bridgeSecurity.setSettingsChanged(false);
|
||||
}
|
||||
String jsonValue = aRenderer.render(newBridgeSettings);
|
||||
configWriter(jsonValue, configPath);
|
||||
_loadConfig(configPath);
|
||||
@@ -213,13 +249,25 @@ public class BridgeSettings extends BackupHandler {
|
||||
log.debug("Save HA Bridge settings.");
|
||||
Path configPath = Paths.get(theBridgeSettings.getConfigfile());
|
||||
JsonTransformer aRenderer = new JsonTransformer();
|
||||
if(bridgeSecurity.isSettingsChanged()) {
|
||||
try {
|
||||
theBridgeSettings.setSecurityData(bridgeSecurity.getSecurityDescriptorData());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.warn("could not get encoded security data: " + e.getMessage());
|
||||
return;
|
||||
} catch (GeneralSecurityException e) {
|
||||
log.warn("could not get encoded security data: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
bridgeSecurity.setSettingsChanged(false);
|
||||
}
|
||||
String jsonValue = aRenderer.render(theBridgeSettings);
|
||||
configWriter(jsonValue, configPath);
|
||||
_loadConfig(configPath);
|
||||
}
|
||||
|
||||
|
||||
private void configWriter(String content, Path filePath) {
|
||||
private synchronized void configWriter(String content, Path filePath) {
|
||||
if(Files.exists(filePath) && !Files.isWritable(filePath)){
|
||||
log.error("Error file is not writable: " + filePath);
|
||||
return;
|
||||
@@ -236,7 +284,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
try {
|
||||
Path target = null;
|
||||
if(Files.exists(filePath)) {
|
||||
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "habridge.config.old");
|
||||
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "habridge.config.old." + getCurrentDate());
|
||||
Files.move(filePath, target);
|
||||
}
|
||||
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
|
||||
@@ -249,7 +297,9 @@ public class BridgeSettings extends BackupHandler {
|
||||
perms.add(PosixFilePermission.OWNER_WRITE);
|
||||
|
||||
try {
|
||||
Files.setPosixFilePermissions(filePath, perms);
|
||||
String osName = System.getProperty("os.name");
|
||||
if(osName.toLowerCase().indexOf("win") < 0)
|
||||
Files.setPosixFilePermissions(filePath, perms);
|
||||
} catch(UnsupportedOperationException e) {
|
||||
log.info("Cannot set permissions for config file on this system as it is not supported. Continuing");
|
||||
}
|
||||
@@ -284,6 +334,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
log.error("checkIpAddress cannot get ip address of this host, Exiting with message: " + e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
|
||||
String addressString = null;
|
||||
InetAddress address = null;
|
||||
while (ifs.hasMoreElements() && addressString == null) {
|
||||
@@ -310,9 +361,4 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
return addressString;
|
||||
}
|
||||
private void setupInternalTestUser() {
|
||||
theBridgeSettings.setupInternalTestUser();
|
||||
if(theBridgeSettings.isSettingsChanged())
|
||||
this.updateConfigFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +1,104 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.UUID;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import com.bwssystems.HABridge.api.hue.HueConstants;
|
||||
import com.bwssystems.HABridge.api.hue.HueError;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
|
||||
|
||||
public class BridgeSettingsDescriptor {
|
||||
private static final String DEFAULT_INTERNAL_USER = "thehabridgeuser";
|
||||
private static final String DEFAULT_USER_DESCRIPTION = "default_test_user";
|
||||
@SerializedName("upnpconfigaddress")
|
||||
@Expose
|
||||
private String upnpconfigaddress;
|
||||
@SerializedName("serverport")
|
||||
@Expose
|
||||
private Integer serverport;
|
||||
@SerializedName("upnpresponseport")
|
||||
@Expose
|
||||
private Integer upnpresponseport;
|
||||
@SerializedName("upnpdevicedb")
|
||||
@Expose
|
||||
private String upnpdevicedb;
|
||||
@SerializedName("veraaddress")
|
||||
@Expose
|
||||
private IpList veraaddress;
|
||||
@SerializedName("harmonyaddress")
|
||||
@Expose
|
||||
private IpList harmonyaddress;
|
||||
@SerializedName("buttonsleep")
|
||||
@Expose
|
||||
private Integer buttonsleep;
|
||||
@SerializedName("upnpstrict")
|
||||
@Expose
|
||||
private boolean upnpstrict;
|
||||
@SerializedName("traceupnp")
|
||||
@Expose
|
||||
private boolean traceupnp;
|
||||
@SerializedName("nestuser")
|
||||
@Expose
|
||||
private String nestuser;
|
||||
@SerializedName("nestpwd")
|
||||
@Expose
|
||||
private String nestpwd;
|
||||
@SerializedName("farenheit")
|
||||
@Expose
|
||||
private boolean farenheit;
|
||||
@SerializedName("configfile")
|
||||
@Expose
|
||||
private String configfile;
|
||||
@SerializedName("numberoflogmessages")
|
||||
@Expose
|
||||
private Integer numberoflogmessages;
|
||||
@SerializedName("hueaddress")
|
||||
@Expose
|
||||
private IpList hueaddress;
|
||||
@SerializedName("haladdress")
|
||||
@Expose
|
||||
private IpList haladdress;
|
||||
@SerializedName("haltoken")
|
||||
@Expose
|
||||
private String haltoken;
|
||||
@SerializedName("whitelist")
|
||||
@Expose
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
@SerializedName("myechourl")
|
||||
@Expose
|
||||
private String myechourl;
|
||||
@SerializedName("webaddress")
|
||||
@Expose
|
||||
private String webaddress;
|
||||
@SerializedName("mqttaddress")
|
||||
@Expose
|
||||
private IpList mqttaddress;
|
||||
@SerializedName("hassaddress")
|
||||
@Expose
|
||||
private IpList hassaddress;
|
||||
@SerializedName("domoticzaddress")
|
||||
@Expose
|
||||
private IpList domoticzaddress;
|
||||
@SerializedName("somfyaddress")
|
||||
@Expose
|
||||
private IpList somfyaddress;
|
||||
@SerializedName("hubversion")
|
||||
@Expose
|
||||
private String hubversion;
|
||||
@SerializedName("securityData")
|
||||
@Expose
|
||||
private String securityData;
|
||||
|
||||
|
||||
private boolean settingsChanged;
|
||||
private boolean veraconfigured;
|
||||
private boolean harmonyconfigured;
|
||||
private boolean nestconfigured;
|
||||
private boolean farenheit;
|
||||
private String configfile;
|
||||
private Integer numberoflogmessages;
|
||||
private IpList hueaddress;
|
||||
private boolean hueconfigured;
|
||||
private IpList haladdress;
|
||||
private String haltoken;
|
||||
private boolean nestconfigured;
|
||||
private boolean halconfigured;
|
||||
private Map<String, WhitelistEntry> whitelist;
|
||||
private boolean settingsChanged;
|
||||
private String myechourl;
|
||||
private String webaddress;
|
||||
private IpList mqttaddress;
|
||||
private boolean mqttconfigured;
|
||||
private IpList hassaddress;
|
||||
private boolean hassconfigured;
|
||||
private String hubversion;
|
||||
private IpList domoticzaddress;
|
||||
private boolean domoticzconfigured;
|
||||
private IpList somfyaddress;
|
||||
private boolean somfyconfigured;
|
||||
|
||||
private boolean lifxconfigured;
|
||||
|
||||
public BridgeSettingsDescriptor() {
|
||||
@@ -226,8 +273,8 @@ public class BridgeSettingsDescriptor {
|
||||
public Map<String, WhitelistEntry> getWhitelist() {
|
||||
return whitelist;
|
||||
}
|
||||
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
|
||||
this.whitelist = whitelist;
|
||||
protected void removeWhitelist() {
|
||||
whitelist = null;
|
||||
}
|
||||
public boolean isSettingsChanged() {
|
||||
return settingsChanged;
|
||||
@@ -295,6 +342,12 @@ public class BridgeSettingsDescriptor {
|
||||
public void setLifxconfigured(boolean lifxconfigured) {
|
||||
this.lifxconfigured = lifxconfigured;
|
||||
}
|
||||
public String getSecurityData() {
|
||||
return securityData;
|
||||
}
|
||||
public void setSecurityData(String securityData) {
|
||||
this.securityData = securityData;
|
||||
}
|
||||
public Boolean isValidVera() {
|
||||
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
@@ -371,80 +424,4 @@ public class BridgeSettingsDescriptor {
|
||||
public Boolean isValidLifx() {
|
||||
return this.isLifxconfigured();
|
||||
}
|
||||
|
||||
public HueError[] validateWhitelistUser(String aUser, String userDescription, boolean strict) {
|
||||
String validUser = null;
|
||||
boolean found = false;
|
||||
if (aUser != null && !aUser.equalsIgnoreCase("undefined") && !aUser.equalsIgnoreCase("null")
|
||||
&& !aUser.equalsIgnoreCase("")) {
|
||||
if (whitelist != null) {
|
||||
Set<String> theUserIds = whitelist.keySet();
|
||||
Iterator<String> userIterator = theUserIds.iterator();
|
||||
while (userIterator.hasNext()) {
|
||||
validUser = userIterator.next();
|
||||
if (validUser.equals(aUser))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!found && !strict) {
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return HueErrorResponse.createResponse("1", "/api/" + aUser, "unauthorized user", null, null, null).getTheErrors();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void newWhitelistUser(String aUser, String userDescription) {
|
||||
if (whitelist == null) {
|
||||
whitelist = new HashMap<>();
|
||||
}
|
||||
if(userDescription == null)
|
||||
userDescription = "auto insert user";
|
||||
|
||||
whitelist.put(aUser, WhitelistEntry.createEntry(userDescription));
|
||||
setSettingsChanged(true);
|
||||
}
|
||||
|
||||
public String createWhitelistUser(String userDescription) {
|
||||
String aUser = getNewUserID();
|
||||
newWhitelistUser(aUser, userDescription);
|
||||
return aUser;
|
||||
}
|
||||
|
||||
private String getNewUserID() {
|
||||
UUID uid = UUID.randomUUID();
|
||||
StringTokenizer st = new StringTokenizer(uid.toString(), "-");
|
||||
String newUser = "";
|
||||
while (st.hasMoreTokens()) {
|
||||
newUser = newUser + st.nextToken();
|
||||
}
|
||||
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public String getInternalTestUser() {
|
||||
return DEFAULT_INTERNAL_USER;
|
||||
}
|
||||
|
||||
public void setupInternalTestUser() {
|
||||
boolean found = false;
|
||||
if(whitelist != null) {
|
||||
for (String key : whitelist.keySet()) {
|
||||
if(key.equals(DEFAULT_INTERNAL_USER)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
newWhitelistUser(DEFAULT_INTERNAL_USER, DEFAULT_USER_DESCRIPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ public class HABridge {
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting....");
|
||||
|
||||
bridgeSettings = new BridgeSettings();
|
||||
// sparkjava config directive to set html static file location for Jetty
|
||||
staticFileLocation("/public");
|
||||
while(!bridgeSettings.getBridgeControl().isStop()) {
|
||||
bridgeSettings.buildSettings();
|
||||
log.info("HA Bridge initializing....");
|
||||
@@ -52,8 +54,9 @@ public class HABridge {
|
||||
ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress());
|
||||
// sparkjava config directive to set port for the web server to listen on
|
||||
port(bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
|
||||
// sparkjava config directive to set html static file location for Jetty
|
||||
staticFileLocation("/public");
|
||||
if(!bridgeSettings.getBridgeControl().isReinit())
|
||||
init();
|
||||
bridgeSettings.getBridgeControl().setReinit(false);
|
||||
// setup system control api first
|
||||
theSystem = new SystemControl(bridgeSettings, theVersion);
|
||||
theSystem.setupServer();
|
||||
@@ -65,9 +68,9 @@ public class HABridge {
|
||||
else {
|
||||
//Setup the device connection homes through the manager
|
||||
homeManager = new HomeManager();
|
||||
homeManager.buildHomes(bridgeSettings.getBridgeSettingsDescriptor(), udpSender);
|
||||
homeManager.buildHomes(bridgeSettings, udpSender);
|
||||
// setup the class to handle the resource setup rest api
|
||||
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), homeManager);
|
||||
theResources = new DeviceResource(bridgeSettings, homeManager);
|
||||
// setup the class to handle the upnp response rest api
|
||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
theSettingResponder.setupServer();
|
||||
@@ -89,9 +92,19 @@ public class HABridge {
|
||||
udpSender.closeResponseSocket();
|
||||
udpSender = null;
|
||||
}
|
||||
bridgeSettings.getBridgeControl().setReinit(false);
|
||||
stop();
|
||||
if(!bridgeSettings.getBridgeControl().isStop()) {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
bridgeSettings.getBridgeSecurity().removeTestUsers();
|
||||
if(bridgeSettings.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettings.updateConfigFile();
|
||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@ import com.bwssystems.HABridge.devicemanagmeent.ResourceHandler;
|
||||
import com.bwssystems.HABridge.hue.HueMulatorHandler;
|
||||
|
||||
public interface Home extends HueMulatorHandler, ResourceHandler {
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings);
|
||||
public Home createHome(BridgeSettings bridgeSettings);
|
||||
public void closeHome();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class HomeManager {
|
||||
}
|
||||
|
||||
// factory method
|
||||
public void buildHomes(BridgeSettingsDescriptor bridgeSettings, UDPDatagramSender aUdpDatagramSender) {
|
||||
public void buildHomes(BridgeSettings bridgeSettings, UDPDatagramSender aUdpDatagramSender) {
|
||||
Home aHome = null;
|
||||
//setup the harmony connection if available
|
||||
aHome = new HarmonyHome(bridgeSettings);
|
||||
|
||||
26
src/main/java/com/bwssystems/HABridge/LinkButtonPressed.java
Normal file
26
src/main/java/com/bwssystems/HABridge/LinkButtonPressed.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LinkButtonPressed extends TimerTask {
|
||||
private static final Logger log = LoggerFactory.getLogger(LinkButtonPressed.class);
|
||||
private BridgeControlDescriptor linkDescriptor;
|
||||
private Timer myTimer;
|
||||
|
||||
public LinkButtonPressed(BridgeControlDescriptor theDescriptor, Timer aTimer) {
|
||||
linkDescriptor = theDescriptor;
|
||||
myTimer = aTimer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
log.info("Link button time ended....");
|
||||
linkDescriptor.setLinkButton(false);
|
||||
myTimer.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
22
src/main/java/com/bwssystems/HABridge/LoginResult.java
Normal file
22
src/main/java/com/bwssystems/HABridge/LoginResult.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
public class LoginResult {
|
||||
|
||||
private String error;
|
||||
|
||||
private User user;
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
}
|
||||
26
src/main/java/com/bwssystems/HABridge/SecurityInfo.java
Normal file
26
src/main/java/com/bwssystems/HABridge/SecurityInfo.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
public class SecurityInfo {
|
||||
private boolean useLinkButton;
|
||||
private boolean secureHueApi;
|
||||
private boolean isSecure;
|
||||
|
||||
public boolean isUseLinkButton() {
|
||||
return useLinkButton;
|
||||
}
|
||||
public void setUseLinkButton(boolean useLinkButton) {
|
||||
this.useLinkButton = useLinkButton;
|
||||
}
|
||||
public boolean isSecureHueApi() {
|
||||
return secureHueApi;
|
||||
}
|
||||
public void setSecureHueApi(boolean secureHueApi) {
|
||||
this.secureHueApi = secureHueApi;
|
||||
}
|
||||
public boolean isSecure() {
|
||||
return isSecure;
|
||||
}
|
||||
public void setSecure(boolean isSecure) {
|
||||
this.isSecure = isSecure;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import static spark.Spark.get;
|
||||
import static spark.Spark.options;
|
||||
import static spark.Spark.post;
|
||||
import static spark.Spark.put;
|
||||
import static spark.Spark.before;
|
||||
import static spark.Spark.halt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
@@ -12,6 +14,8 @@ import java.net.MulticastSocket;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Timer;
|
||||
import java.util.Base64;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.slf4j.Logger;
|
||||
@@ -55,24 +59,28 @@ public class SystemControl {
|
||||
// This function sets up the sparkjava rest calls for the hue api
|
||||
public void setupServer() {
|
||||
log.info("System control service started....");
|
||||
before(SYSTEM_CONTEXT + "/*", (request, response) -> {
|
||||
if(bridgeSettings.getBridgeSecurity().isSecure()) {
|
||||
String pathInfo = request.pathInfo();
|
||||
if(pathInfo == null || (!pathInfo.equals(SYSTEM_CONTEXT + "/login") && !pathInfo.equals(SYSTEM_CONTEXT + "/habridge/version"))) {
|
||||
User authUser = bridgeSettings.getBridgeSecurity().getAuthenticatedUser(request);
|
||||
if(authUser == null) {
|
||||
halt(401, "{\"message\":\"User not authenticated\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// http://ip_address:port/system/habridge/version gets the version of this bridge instance
|
||||
get (SYSTEM_CONTEXT + "/habridge/version", "application/json", (request, response) -> {
|
||||
get (SYSTEM_CONTEXT + "/habridge/version", (request, response) -> {
|
||||
log.debug("Get HA Bridge version: v" + version.getVersion());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return "{\"version\":\"" + version.getVersion() + "\"}";
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/habridge/testuser gets the valid test user for calling the api
|
||||
get (SYSTEM_CONTEXT + "/habridge/testuser", "application/json", (request, response) -> {
|
||||
log.debug("Get HA Bridge testuser: " + bridgeSettings.getBridgeSettingsDescriptor().getInternalTestUser());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return "{\"user\":\"" + bridgeSettings.getBridgeSettingsDescriptor().getInternalTestUser() + "\"}";
|
||||
response.type("application/json");
|
||||
return "{\"version\":\"" + version.getVersion() + "\",\"isSecure\":" + bridgeSettings.getBridgeSecurity().isSecure() + "}";
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/logmsgs gets the log messages for the bridge
|
||||
get (SYSTEM_CONTEXT + "/logmsgs", "application/json", (request, response) -> {
|
||||
get (SYSTEM_CONTEXT + "/logmsgs", (request, response) -> {
|
||||
log.debug("Get logmsgs.");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
String logMsgs;
|
||||
int count = -1;
|
||||
if(cyclicBufferAppender == null)
|
||||
@@ -93,24 +101,190 @@ public class SystemControl {
|
||||
}
|
||||
}
|
||||
logMsgs = logMsgs + "]";
|
||||
response.status(200);
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return logMsgs;
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/logmgmt/loggers gets the logger info for the bridge
|
||||
get (SYSTEM_CONTEXT + "/logmgmt/loggers/:all", "application/json", (request, response) -> {
|
||||
get (SYSTEM_CONTEXT + "/logmgmt/loggers/:all", (request, response) -> {
|
||||
log.debug("Get loggers info with showAll argument: " + request.params(":all"));
|
||||
Boolean showAll = false;
|
||||
if(request.params(":all").equals("true"))
|
||||
showAll = true;
|
||||
theLogServiceMgr.setShowAll(showAll);
|
||||
theLogServiceMgr.init();
|
||||
response.status(200);
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return theLogServiceMgr.getConfiguredLoggers();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/setpassword CORS request
|
||||
options(SYSTEM_CONTEXT + "/setpassword", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/setpassword which sets a password for a given user
|
||||
post(SYSTEM_CONTEXT + "/setpassword", (request, response) -> {
|
||||
log.debug("setpassword....");
|
||||
String theDecodedPayload = new String(Base64.getDecoder().decode(request.body()));
|
||||
User theUser = new Gson().fromJson(theDecodedPayload, User.class);
|
||||
String errorMessage = bridgeSettings.getBridgeSecurity().setPassword(theUser);
|
||||
if(errorMessage != null) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "{\"message\":\"" + errorMessage + "\"}";
|
||||
} else {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
}
|
||||
|
||||
if(errorMessage == null)
|
||||
errorMessage = "{}";
|
||||
response.type("application/json");
|
||||
return errorMessage;
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/adduser CORS request
|
||||
options(SYSTEM_CONTEXT + "/adduser", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/adduser which adds a new user
|
||||
put(SYSTEM_CONTEXT + "/adduser", (request, response) -> {
|
||||
log.debug("adduser....");
|
||||
String theDecodedPayload = new String(Base64.getDecoder().decode(request.body()));
|
||||
User theUser = new Gson().fromJson(theDecodedPayload, User.class);
|
||||
String errorMessage = theUser.validate();
|
||||
if(errorMessage != null) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "{\"message\":\"" + errorMessage + "\"}";
|
||||
} else {
|
||||
errorMessage = bridgeSettings.getBridgeSecurity().addUser(theUser);
|
||||
if(errorMessage == null) {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
} else {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "{\"message\":\"" + errorMessage + "\"}";
|
||||
}
|
||||
}
|
||||
|
||||
if(errorMessage == null)
|
||||
errorMessage = "{}";
|
||||
response.type("application/json");
|
||||
return errorMessage;
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/deluser CORS request
|
||||
options(SYSTEM_CONTEXT + "/deluser", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/deluser which dels a user
|
||||
put(SYSTEM_CONTEXT + "/deluser", (request, response) -> {
|
||||
log.debug("deluser....");
|
||||
String theDecodedPayload = new String(Base64.getDecoder().decode(request.body()));
|
||||
User theUser = new Gson().fromJson(theDecodedPayload, User.class);
|
||||
String errorMessage = bridgeSettings.getBridgeSecurity().delUser(theUser);
|
||||
if(errorMessage != null) {
|
||||
response.status(HttpStatus.SC_BAD_REQUEST);
|
||||
errorMessage = "{\"message\":\"" + errorMessage + "\"}";
|
||||
} else {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
}
|
||||
|
||||
if(errorMessage == null)
|
||||
errorMessage = "{}";
|
||||
response.type("application/json");
|
||||
return errorMessage;
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/login CORS request
|
||||
options(SYSTEM_CONTEXT + "/login", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/login validates the login
|
||||
post(SYSTEM_CONTEXT + "/login", (request, response) -> {
|
||||
log.debug("login....");
|
||||
String theDecodedPayload = new String(Base64.getDecoder().decode(request.body()));
|
||||
User theUser = new Gson().fromJson(theDecodedPayload, User.class);
|
||||
LoginResult result = bridgeSettings.getBridgeSecurity().validatePassword(theUser);
|
||||
if(result.getUser() != null)
|
||||
bridgeSettings.getBridgeSecurity().addAuthenticatedUser(request, theUser);
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return result;
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/presslinkbutton CORS request
|
||||
options(SYSTEM_CONTEXT + "/presslinkbutton", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/presslinkbutton which sets the link button for device registration
|
||||
put(SYSTEM_CONTEXT + "/presslinkbutton", (request, response) -> {
|
||||
log.info("Link button pressed....");
|
||||
bridgeSettings.getBridgeControl().setLinkButton(true);
|
||||
Timer theTimer = new Timer();
|
||||
theTimer.schedule(new LinkButtonPressed(bridgeSettings.getBridgeControl(), theTimer), 30000);
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return "";
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/securityinfo gets the security info for the bridge
|
||||
get (SYSTEM_CONTEXT + "/securityinfo", (request, response) -> {
|
||||
log.debug("Get security info");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/changesecurityinfo CORS request
|
||||
options(SYSTEM_CONTEXT + "/changesecurityinfo", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/changesecurityinfo which sets the security settings other than passwords and users
|
||||
post(SYSTEM_CONTEXT + "/changesecurityinfo", (request, response) -> {
|
||||
log.debug("changesecurityinfo....");
|
||||
SecurityInfo theInfo = new Gson().fromJson(request.body(), SecurityInfo.class);
|
||||
bridgeSettings.getBridgeSecurity().setUseLinkButton(theInfo.isUseLinkButton());
|
||||
bridgeSettings.getBridgeSecurity().setSecureHueApi(theInfo.isSecureHueApi());
|
||||
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/logmgmt/update CORS request
|
||||
options(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (request, response) -> {
|
||||
options(SYSTEM_CONTEXT + "/logmgmt/update", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
@@ -119,28 +293,28 @@ public class SystemControl {
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/logmgmt/update which changes logging parameters for the process
|
||||
put(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (request, response) -> {
|
||||
put(SYSTEM_CONTEXT + "/logmgmt/update", (request, response) -> {
|
||||
log.debug("update loggers: " + request.body());
|
||||
response.status(200);
|
||||
LoggerInfo updateLoggers[];
|
||||
updateLoggers = new Gson().fromJson(request.body(), LoggerInfo[].class);
|
||||
LoggingForm theModel = theLogServiceMgr.getModel();
|
||||
theModel.setUpdatedLoggers(Arrays.asList(updateLoggers));
|
||||
theLogServiceMgr.updateLogLevels();
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return theLogServiceMgr.getConfiguredLoggers();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/settings which returns the bridge configuration settings
|
||||
get(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
|
||||
get(SYSTEM_CONTEXT + "/settings", (request, response) -> {
|
||||
log.debug("bridge settings requested from " + request.ip());
|
||||
|
||||
response.status(200);
|
||||
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/settings CORS request
|
||||
options(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
|
||||
options(SYSTEM_CONTEXT + "/settings", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
@@ -149,17 +323,17 @@ public class SystemControl {
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/settings which returns the bridge configuration settings
|
||||
put(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
|
||||
put(SYSTEM_CONTEXT + "/settings", (request, response) -> {
|
||||
log.debug("save bridge settings requested from " + request.ip() + " with body: " + request.body());
|
||||
BridgeSettingsDescriptor newBridgeSettings = new Gson().fromJson(request.body(), BridgeSettingsDescriptor.class);
|
||||
bridgeSettings.save(newBridgeSettings);
|
||||
response.status(200);
|
||||
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/control/reinit CORS request
|
||||
options(SYSTEM_CONTEXT + "/control/reinit", "application/json", (request, response) -> {
|
||||
options(SYSTEM_CONTEXT + "/control/reinit", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
@@ -168,12 +342,14 @@ public class SystemControl {
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/control/reinit sets the parameter reinit the server
|
||||
put(SYSTEM_CONTEXT + "/control/reinit", "application/json", (request, response) -> {
|
||||
put(SYSTEM_CONTEXT + "/control/reinit", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return reinit();
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/control/stop CORS request
|
||||
options(SYSTEM_CONTEXT + "/control/stop", "application/json", (request, response) -> {
|
||||
options(SYSTEM_CONTEXT + "/control/stop", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
|
||||
@@ -182,19 +358,22 @@ public class SystemControl {
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/system/control/stop sets the parameter stop the server
|
||||
put(SYSTEM_CONTEXT + "/control/stop", "application/json", (request, response) -> {
|
||||
put(SYSTEM_CONTEXT + "/control/stop", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return stop();
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/backup/available returns a list of config backup filenames
|
||||
get (SYSTEM_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
||||
get (SYSTEM_CONTEXT + "/backup/available", (request, response) -> {
|
||||
log.debug("Get backup filenames");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBackups();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/backup/create CORS request
|
||||
options(SYSTEM_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
||||
options(SYSTEM_CONTEXT + "/backup/create", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "PUT");
|
||||
@@ -202,16 +381,18 @@ public class SystemControl {
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
put (SYSTEM_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
||||
put (SYSTEM_CONTEXT + "/backup/create", (request, response) -> {
|
||||
log.debug("Create backup: " + request.body());
|
||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||
BackupFilename returnFilename = new BackupFilename();
|
||||
returnFilename.setFilename(bridgeSettings.backup(aFilename.getFilename()));
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return returnFilename;
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/backup/delete CORS request
|
||||
options(SYSTEM_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||
options(SYSTEM_CONTEXT + "/backup/delete", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "POST");
|
||||
@@ -219,18 +400,20 @@ public class SystemControl {
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
post (SYSTEM_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
||||
post (SYSTEM_CONTEXT + "/backup/delete", (request, response) -> {
|
||||
log.debug("Delete backup: " + request.body());
|
||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||
if(aFilename != null)
|
||||
bridgeSettings.deleteBackup(aFilename.getFilename());
|
||||
else
|
||||
log.warn("No filename given for delete backup.");
|
||||
return null;
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return "";
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/backup/restore CORS request
|
||||
options(SYSTEM_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||
options(SYSTEM_CONTEXT + "/backup/restore", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.header("Access-Control-Allow-Methods", "POST");
|
||||
@@ -238,7 +421,7 @@ public class SystemControl {
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
post (SYSTEM_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
||||
post (SYSTEM_CONTEXT + "/backup/restore", (request, response) -> {
|
||||
log.debug("Restore backup: " + request.body());
|
||||
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
||||
if(aFilename != null) {
|
||||
@@ -247,6 +430,8 @@ public class SystemControl {
|
||||
}
|
||||
else
|
||||
log.warn("No filename given for restore backup.");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||
}, new JsonTransformer());
|
||||
}
|
||||
|
||||
65
src/main/java/com/bwssystems/HABridge/User.java
Normal file
65
src/main/java/com/bwssystems/HABridge/User.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import spark.utils.StringUtils;
|
||||
|
||||
public class User {
|
||||
private int id;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String password2;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPassword2() {
|
||||
return password2;
|
||||
}
|
||||
|
||||
public void setPassword2(String password2) {
|
||||
this.password2 = password2;
|
||||
}
|
||||
|
||||
public String validate() {
|
||||
String error = null;
|
||||
|
||||
if(StringUtils.isEmpty(username)) {
|
||||
error = "You have to enter a username";
|
||||
} else if(StringUtils.isEmpty(password)) {
|
||||
error = "You have to enter a password";
|
||||
} else if(!password.equals(password2)) {
|
||||
error = "The two passwords do not match";
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
public boolean validatePassword() {
|
||||
if(password != null && password2 != null)
|
||||
return password.equals(password2);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.bwssystems.HABridge.devicemanagmeent;
|
||||
|
||||
import static spark.Spark.get;
|
||||
import static spark.Spark.halt;
|
||||
import static spark.Spark.options;
|
||||
import static spark.Spark.post;
|
||||
import static spark.Spark.put;
|
||||
import static spark.Spark.before;
|
||||
import static spark.Spark.delete;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -15,9 +17,10 @@ import org.apache.http.HttpStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.HomeManager;
|
||||
import com.bwssystems.HABridge.User;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.BackupFilename;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
@@ -36,11 +39,13 @@ public class DeviceResource {
|
||||
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
|
||||
private DeviceRepository deviceRepository;
|
||||
private HomeManager homeManager;
|
||||
private BridgeSettings bridgeSettings;
|
||||
private Gson aGsonHandler;
|
||||
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||
|
||||
public DeviceResource(BridgeSettingsDescriptor theSettings, HomeManager aHomeManager) {
|
||||
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||
public DeviceResource(BridgeSettings theSettings, HomeManager aHomeManager) {
|
||||
bridgeSettings = theSettings;
|
||||
this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb());
|
||||
homeManager = aHomeManager;
|
||||
aGsonHandler = new GsonBuilder().create();
|
||||
setupEndpoints();
|
||||
@@ -52,6 +57,15 @@ public class DeviceResource {
|
||||
|
||||
private void setupEndpoints() {
|
||||
log.info("HABridge device management service started.... ");
|
||||
before(API_CONTEXT + "/*", (request, response) -> {
|
||||
// This never gets called as the HueMulator class covers this path. This is here for backup
|
||||
if(bridgeSettings.getBridgeSecurity().isSecure()) {
|
||||
User authUser = bridgeSettings.getBridgeSecurity().getAuthenticatedUser(request);
|
||||
if(authUser == null) {
|
||||
halt(401, "{\"message\":\"User not authenticated\"}");
|
||||
}
|
||||
}
|
||||
});
|
||||
// http://ip_address:port/api/devices CORS request
|
||||
options(API_CONTEXT, "application/json", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.HomeManager;
|
||||
import com.bwssystems.HABridge.User;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||
@@ -22,7 +23,9 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import static spark.Spark.before;
|
||||
import static spark.Spark.get;
|
||||
import static spark.Spark.halt;
|
||||
import static spark.Spark.options;
|
||||
import static spark.Spark.post;
|
||||
import static spark.Spark.put;
|
||||
@@ -65,6 +68,22 @@ public class HueMulator {
|
||||
// This function sets up the sparkjava rest calls for the hue api
|
||||
public void setupServer() {
|
||||
log.info("Hue emulator service started....");
|
||||
before(HUE_CONTEXT + "/*", (request, response) -> {
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSecure()) {
|
||||
String pathInfo = request.pathInfo();
|
||||
if(pathInfo != null && pathInfo.contains(HUE_CONTEXT + "/devices")) {
|
||||
User authUser = bridgeSettingMaster.getBridgeSecurity().getAuthenticatedUser(request);
|
||||
if(authUser == null) {
|
||||
halt(401, "{\"message\":\"User not authenticated\"}");
|
||||
}
|
||||
} else if (bridgeSettingMaster.getBridgeSecurity().isSecureHueApi()) {
|
||||
User authUser = bridgeSettingMaster.getBridgeSecurity().getAuthenticatedUser(request);
|
||||
if(authUser == null) {
|
||||
halt(401, "{\"message\":\"User not authenticated\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/groups returns json objects of
|
||||
// all groups configured
|
||||
get(HUE_CONTEXT + "/:userid/groups", "application/json", (request, response) -> {
|
||||
@@ -576,9 +595,9 @@ public class HueMulator {
|
||||
|
||||
private String basicListHandler(String type, String userId, String requestIp) {
|
||||
log.debug("hue " + type + " list requested: " + userId + " from " + requestIp);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
return aGsonHandler.toJson(theErrors);
|
||||
@@ -590,9 +609,9 @@ public class HueMulator {
|
||||
log.debug("hue group list requested: " + userId + " from " + requestIp);
|
||||
HueError[] theErrors = null;
|
||||
Map<String, GroupResponse> groupResponseMap = null;
|
||||
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
||||
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
groupResponseMap = new HashMap<String, GroupResponse>();
|
||||
@@ -607,9 +626,9 @@ public class HueMulator {
|
||||
private Object groupsIdHandler(String groupId, String userId, String requestIp) {
|
||||
log.debug("hue group id: <" + groupId + "> requested: " + userId + " from " + requestIp);
|
||||
HueError[] theErrors = null;
|
||||
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
||||
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
if (groupId.equalsIgnoreCase("0")) {
|
||||
@@ -632,9 +651,9 @@ public class HueMulator {
|
||||
if (bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue lights list requested: " + userId + " from " + requestIp);
|
||||
log.debug("hue lights list requested: " + userId + " from " + requestIp);
|
||||
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
||||
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
List<DeviceDescriptor> deviceList = repository.findAllByRequester(requestIp);
|
||||
@@ -642,28 +661,30 @@ public class HueMulator {
|
||||
deviceResponseMap = new HashMap<String, DeviceResponse>();
|
||||
for (DeviceDescriptor device : deviceList) {
|
||||
DeviceResponse deviceResponse = null;
|
||||
if (device.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||
CallItem[] callItems = null;
|
||||
try {
|
||||
if(device.getOnUrl() != null)
|
||||
callItems = aGsonHandler.fromJson(device.getOnUrl(), CallItem[].class);
|
||||
} catch(JsonSyntaxException e) {
|
||||
log.warn("Could not decode Json for url items to get Hue state for device: " + device.getName());
|
||||
callItems = null;
|
||||
}
|
||||
|
||||
for (int i = 0; callItems != null && i < callItems.length; i++) {
|
||||
if((callItems[i].getType() != null && callItems[i].getType().equals(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) ||
|
||||
(callItems[i].getItem().getAsString().contains("hueName"))) {
|
||||
deviceResponse = myHueHome.getHueDeviceInfo(callItems[i], device);
|
||||
i = callItems.length;
|
||||
if(!device.isInactive()) {
|
||||
if (device.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||
CallItem[] callItems = null;
|
||||
try {
|
||||
if(device.getOnUrl() != null)
|
||||
callItems = aGsonHandler.fromJson(device.getOnUrl(), CallItem[].class);
|
||||
} catch(JsonSyntaxException e) {
|
||||
log.warn("Could not decode Json for url items to get Hue state for device: " + device.getName());
|
||||
callItems = null;
|
||||
}
|
||||
|
||||
for (int i = 0; callItems != null && i < callItems.length; i++) {
|
||||
if((callItems[i].getType() != null && callItems[i].getType().equals(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) ||
|
||||
(callItems[i].getItem().getAsString().contains("hueName"))) {
|
||||
deviceResponse = myHueHome.getHueDeviceInfo(callItems[i], device);
|
||||
i = callItems.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceResponse == null)
|
||||
deviceResponse = DeviceResponse.createResponse(device);
|
||||
deviceResponseMap.put(device.getId(), deviceResponse);
|
||||
}
|
||||
|
||||
if (deviceResponse == null)
|
||||
deviceResponse = DeviceResponse.createResponse(device);
|
||||
deviceResponseMap.put(device.getId(), deviceResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,50 +698,58 @@ public class HueMulator {
|
||||
UserCreateRequest aNewUser = null;
|
||||
String newUser = null;
|
||||
String aDeviceType = null;
|
||||
boolean toContinue = false;
|
||||
|
||||
if (bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue api user create requested: " + body + " from " + ipAddress);
|
||||
log.debug("hue api user create requested: " + body + " from " + ipAddress);
|
||||
|
||||
if (body != null && !body.isEmpty()) {
|
||||
try {
|
||||
aNewUser = aGsonHandler.fromJson(body, UserCreateRequest.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not add user. Request garbled: " + body);
|
||||
return aGsonHandler.toJson(HueErrorResponse.createResponse("2", "/",
|
||||
"Could not add user.", null, null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
newUser = aNewUser.getUsername();
|
||||
aDeviceType = aNewUser.getDevicetype();
|
||||
}
|
||||
|
||||
if (aDeviceType == null)
|
||||
aDeviceType = "<not given>";
|
||||
|
||||
if (newUser == null) {
|
||||
newUser = bridgeSettings.createWhitelistUser(aDeviceType);
|
||||
}
|
||||
else {
|
||||
bridgeSettings.validateWhitelistUser(newUser, aDeviceType, false);
|
||||
}
|
||||
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
if (bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue api user create requested for device type: " + aDeviceType + " and username: "
|
||||
+ newUser + (followingSlash ? " /api/ called" : ""));
|
||||
log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser + (followingSlash ? " /api/ called" : ""));
|
||||
|
||||
return "[{\"success\":{\"username\":\"" + newUser + "\"}}]";
|
||||
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isUseLinkButton() && bridgeSettingMaster.getBridgeControl().isLinkButton())
|
||||
toContinue = true;
|
||||
else if(!bridgeSettingMaster.getBridgeSecurity().isUseLinkButton())
|
||||
toContinue = true;
|
||||
|
||||
if(toContinue) {
|
||||
log.debug("hue api user create requested: " + body + " from " + ipAddress);
|
||||
|
||||
if (body != null && !body.isEmpty()) {
|
||||
try {
|
||||
aNewUser = aGsonHandler.fromJson(body, UserCreateRequest.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not add user. Request garbled: " + body);
|
||||
return aGsonHandler.toJson(HueErrorResponse.createResponse("2", "/",
|
||||
"Could not add user.", null, null, null).getTheErrors(), HueError[].class);
|
||||
}
|
||||
newUser = aNewUser.getUsername();
|
||||
aDeviceType = aNewUser.getDevicetype();
|
||||
}
|
||||
|
||||
if (aDeviceType == null)
|
||||
aDeviceType = "<not given>";
|
||||
|
||||
if (newUser == null) {
|
||||
newUser = bridgeSettingMaster.getBridgeSecurity().createWhitelistUser(aDeviceType);
|
||||
}
|
||||
else {
|
||||
bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(newUser, aDeviceType, false);
|
||||
}
|
||||
|
||||
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
|
||||
if (bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue api user create requested for device type: " + aDeviceType + " and username: "
|
||||
+ newUser + (followingSlash ? " /api/ called" : ""));
|
||||
log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser + (followingSlash ? " /api/ called" : ""));
|
||||
return "[{\"success\":{\"username\":\"" + newUser + "\"}}]";
|
||||
}
|
||||
return aGsonHandler.toJson(HueErrorResponse.createResponse("1", "/api/", "unauthorized user", null, null, null).getTheErrors());
|
||||
}
|
||||
|
||||
private Object getConfig(String userId, String ipAddress) {
|
||||
if (bridgeSettings.isTraceupnp())
|
||||
log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + ipAddress);
|
||||
log.debug("hue api config requested: " + userId + " from " + ipAddress);
|
||||
if (bridgeSettings.validateWhitelistUser(userId, null, true) != null) {
|
||||
if (bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()) != null) {
|
||||
log.debug("hue api config requested, No User supplied, returning public config");
|
||||
HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue",
|
||||
bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion());
|
||||
@@ -736,7 +765,7 @@ public class HueMulator {
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object getFullState(String userId, String ipAddress) {
|
||||
log.debug("hue api full state requested: " + userId + " from " + ipAddress);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, true);
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null)
|
||||
return theErrors;
|
||||
|
||||
@@ -750,7 +779,7 @@ public class HueMulator {
|
||||
|
||||
private Object getLight(String userId, String lightId, String ipAddress) {
|
||||
log.debug("hue light requested: " + lightId + " for user: " + userId + " from " + ipAddress);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, true);
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null)
|
||||
return theErrors;
|
||||
|
||||
@@ -794,7 +823,7 @@ public class HueMulator {
|
||||
Integer targetBri = null;
|
||||
Integer targetBriInc = null;
|
||||
log.debug("Update state requested: " + userId + " from " + ipAddress + " body: " + body);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, true);
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null)
|
||||
return aGsonHandler.toJson(theErrors);
|
||||
try {
|
||||
@@ -844,7 +873,7 @@ public class HueMulator {
|
||||
aMultiUtil.setDelayDefault(bridgeSettings.getButtonsleep());
|
||||
aMultiUtil.setSetCount(1);
|
||||
log.debug("hue state change requested: " + userId + " from " + ipAddress + " body: " + body);
|
||||
HueError[] theErrors = bridgeSettings.validateWhitelistUser(userId, null, true);
|
||||
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null)
|
||||
return aGsonHandler.toJson(theErrors);
|
||||
try {
|
||||
@@ -954,6 +983,9 @@ public class HueMulator {
|
||||
else
|
||||
aMultiUtil.setTheDelay(aMultiUtil.getDelayDefault());
|
||||
responseString = homeManager.findHome(callItems[i].getType().trim()).deviceHandler(callItems[i], aMultiUtil, lightId, state.getBri(), targetBri, targetBriInc, device, body);
|
||||
if(responseString != null && responseString.contains("{\"error\":")) {
|
||||
x = aMultiUtil.getSetCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
@@ -32,7 +32,7 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
||||
private Boolean isFarenheit;
|
||||
private Boolean validNest;
|
||||
|
||||
public NestHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public NestHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -164,20 +164,20 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.bwssystems.HABridge.Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public com.bwssystems.HABridge.Home createHome(BridgeSettings bridgeSettings) {
|
||||
theSession = null;
|
||||
theNest = null;
|
||||
nestItems = null;
|
||||
validNest = bridgeSettings.isValidNest();
|
||||
validNest = bridgeSettings.getBridgeSettingsDescriptor().isValidNest();
|
||||
aGsonHandler = null;
|
||||
log.info("Nest Home created." + (validNest ? "" : " No Nest configured."));
|
||||
|
||||
if(validNest) {
|
||||
aGsonHandler = new GsonBuilder().create();
|
||||
|
||||
isFarenheit = bridgeSettings.isFarenheit();
|
||||
isFarenheit = bridgeSettings.getBridgeSettingsDescriptor().isFarenheit();
|
||||
try {
|
||||
theSession = new NestSession(bridgeSettings.getNestuser(), bridgeSettings.getNestpwd());
|
||||
theSession = new NestSession(bridgeSettings.getBridgeSettingsDescriptor().getNestuser(), bridgeSettings.getBridgeSettingsDescriptor().getNestpwd());
|
||||
theNest = new Nest(theSession);
|
||||
} catch (LoginException e) {
|
||||
log.error("Caught Login Exception, setting Nest to invalid....");
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
@@ -27,7 +27,7 @@ public class DomoticzHome implements Home {
|
||||
private Boolean validDomoticz;
|
||||
private HTTPHandler httpClient;
|
||||
|
||||
public DomoticzHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public DomoticzHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -123,14 +123,14 @@ public class DomoticzHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
validDomoticz = bridgeSettings.isValidDomoticz();
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
validDomoticz = bridgeSettings.getBridgeSettingsDescriptor().isValidDomoticz();
|
||||
log.info("Domoticz Home created." + (validDomoticz ? "" : " No Domoticz devices configured."));
|
||||
if(!validDomoticz)
|
||||
return null;
|
||||
httpClient = new HTTPHandler();
|
||||
domoticzs = new HashMap<String, DomoticzHandler>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getDomoticzaddress().getDevices().iterator();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getDomoticzaddress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aDomoticz = theList.next();
|
||||
try {
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.io.IOException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
@@ -16,15 +16,16 @@ import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
|
||||
public class CommandHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(CommandHome.class);
|
||||
private BridgeSettings theSettings;
|
||||
|
||||
public CommandHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public CommandHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int itensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) {
|
||||
log.debug("Exec Request called with url: " + anItem.getItem().getAsString());
|
||||
log.debug("Exec Request called with url: " + anItem.getItem().getAsString() + " and exec Garden: " + (theSettings.getBridgeSecurity().getExecGarden() == null ? "not given" : theSettings.getBridgeSecurity().getExecGarden()));
|
||||
String responseString = null;
|
||||
String intermediate;
|
||||
if (anItem.getItem().getAsString().contains("exec://"))
|
||||
@@ -34,6 +35,14 @@ public class CommandHome implements Home {
|
||||
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, itensity, targetBri, targetBriInc, false);
|
||||
intermediate = DeviceDataDecode.replaceDeviceData(intermediate, device);
|
||||
intermediate = TimeDecode.replaceTimeValue(intermediate);
|
||||
String execGarden = theSettings.getBridgeSecurity().getExecGarden();
|
||||
if(execGarden != null && !execGarden.trim().isEmpty()) {
|
||||
if(System.getProperty("os.name").toLowerCase().indexOf("win") >= 0)
|
||||
intermediate = execGarden + "\\" + intermediate;
|
||||
else
|
||||
intermediate = execGarden + "/" + intermediate;
|
||||
}
|
||||
|
||||
String anError = doExecRequest(intermediate, lightId);
|
||||
if (anError != null) {
|
||||
responseString = anError;
|
||||
@@ -49,7 +58,7 @@ public class CommandHome implements Home {
|
||||
Process p = Runtime.getRuntime().exec(anItem);
|
||||
log.debug("Process running: " + p.isAlive());
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not execute request: " + anItem, e);
|
||||
log.warn("Could not execute request: " + anItem + " with message: " + e.getMessage());
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
|
||||
+ "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId
|
||||
+ "state\"}}]";
|
||||
@@ -65,8 +74,9 @@ public class CommandHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
log.info("Command Home for system program execution created.");
|
||||
this.theSettings = bridgeSettings;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
@@ -21,7 +21,7 @@ public class HalHome implements Home {
|
||||
private Map<String, HalInfo> hals;
|
||||
private Boolean validHal;
|
||||
|
||||
public HalHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public HalHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -111,17 +111,17 @@ public class HalHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
validHal = bridgeSettings.isValidHal();
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
validHal = bridgeSettings.getBridgeSettingsDescriptor().isValidHal();
|
||||
log.info("HAL Home created." + (validHal ? "" : " No HAL devices configured."));
|
||||
if(!validHal)
|
||||
return null;
|
||||
hals = new HashMap<String, HalInfo>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getHaladdress().getDevices().iterator();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHaladdress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aHal = theList.next();
|
||||
try {
|
||||
hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getHaltoken()));
|
||||
hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getBridgeSettingsDescriptor().getHaltoken()));
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot get hal client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
|
||||
return null;
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.IpList;
|
||||
@@ -32,7 +32,7 @@ public class HarmonyHome implements Home {
|
||||
private Boolean validHarmony;
|
||||
private Gson aGsonHandler;
|
||||
|
||||
public HarmonyHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public HarmonyHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -197,9 +197,9 @@ public class HarmonyHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||
validHarmony = bridgeSettings.isValidHarmony();
|
||||
validHarmony = bridgeSettings.getBridgeSettingsDescriptor().isValidHarmony();
|
||||
log.info("Harmony Home created." + (validHarmony ? "" : " No Harmony devices configured.") + (isDevMode ? " DevMode is set." : ""));
|
||||
if(validHarmony || isDevMode) {
|
||||
hubs = new HashMap<String, HarmonyServer>();
|
||||
@@ -214,16 +214,16 @@ public class HarmonyHome implements Home {
|
||||
theList.add(devModeIp);
|
||||
IpList thedevList = new IpList();
|
||||
thedevList.setDevices(theList);
|
||||
bridgeSettings.setHarmonyAddress(thedevList);
|
||||
bridgeSettings.getBridgeSettingsDescriptor().setHarmonyAddress(thedevList);
|
||||
}
|
||||
Iterator<NamedIP> theList = bridgeSettings.getHarmonyAddress().getDevices().iterator();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHarmonyAddress().getDevices().iterator();
|
||||
while(theList.hasNext() && validHarmony) {
|
||||
NamedIP aHub = theList.next();
|
||||
boolean loopControl = true;
|
||||
int retryCount = 0;
|
||||
while(loopControl) {
|
||||
try {
|
||||
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings, isDevMode, aHub));
|
||||
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings.getBridgeSettingsDescriptor(), isDevMode, aHub));
|
||||
loopControl = false;
|
||||
} catch (Exception e) {
|
||||
if(retryCount > 3) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
@@ -26,23 +26,23 @@ public class HassHome implements Home {
|
||||
private Boolean validHass;
|
||||
private Gson aGsonHandler;
|
||||
|
||||
public HassHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public HassHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
hassMap = null;
|
||||
aGsonHandler = null;
|
||||
validHass = bridgeSettings.isValidHass();
|
||||
validHass = bridgeSettings.getBridgeSettingsDescriptor().isValidHass();
|
||||
log.info("HomeAssistant Home created." + (validHass ? "" : " No HomeAssistants configured."));
|
||||
if(validHass) {
|
||||
hassMap = new HashMap<String,HomeAssistant>();
|
||||
aGsonHandler =
|
||||
new GsonBuilder()
|
||||
.create();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getHassaddress().getDevices().iterator();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHassaddress().getDevices().iterator();
|
||||
while(theList.hasNext() && validHass) {
|
||||
NamedIP aHass = theList.next();
|
||||
try {
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.bwssystems.HABridge.plugins.http;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.api.NameValue;
|
||||
@@ -20,7 +20,7 @@ public class HTTPHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(HTTPHome.class);
|
||||
private HTTPHandler anHttpHandler;
|
||||
|
||||
public HTTPHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public HTTPHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class HTTPHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
anHttpHandler = new HTTPHandler();
|
||||
log.info("Http Home created.");
|
||||
return this;
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
@@ -25,7 +25,7 @@ public class HueHome implements Home {
|
||||
private Boolean validHue;
|
||||
private Gson aGsonHandler;
|
||||
|
||||
public HueHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public HueHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -105,12 +105,12 @@ public class HueHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
validHue = bridgeSettings.isValidHue();
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
validHue = bridgeSettings.getBridgeSettingsDescriptor().isValidHue();
|
||||
log.info("Hue passthru Home created." + (validHue ? "" : " No Hue passtrhu systems configured."));
|
||||
if(validHue) {
|
||||
hues = new HashMap<String, HueInfo>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getHueaddress().getDevices().iterator();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getHueaddress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aHue = theList.next();
|
||||
hues.put(aHue.getName(), new HueInfo(aHue));
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
@@ -38,21 +38,21 @@ public class LifxHome implements Home {
|
||||
private Boolean validLifx;
|
||||
private Gson aGsonHandler;
|
||||
|
||||
public LifxHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public LifxHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
lifxMap = null;
|
||||
aGsonHandler = null;
|
||||
validLifx = bridgeSettings.isValidLifx();
|
||||
validLifx = bridgeSettings.getBridgeSettingsDescriptor().isValidLifx();
|
||||
log.info("LifxDevice Home created." + (validLifx ? "" : " No LifxDevices configured."));
|
||||
if(validLifx) {
|
||||
try {
|
||||
log.info("Open Lifx client....");
|
||||
InetAddress configuredAddress = InetAddress.getByName(bridgeSettings.getUpnpConfigAddress());
|
||||
InetAddress configuredAddress = InetAddress.getByName(bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress());
|
||||
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(configuredAddress);
|
||||
InetAddress bcastInetAddr = null;
|
||||
if (networkInterface != null) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
@@ -26,7 +26,7 @@ public class MQTTHome implements Home {
|
||||
private Boolean validMqtt;
|
||||
private Gson aGsonHandler;
|
||||
|
||||
public MQTTHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public MQTTHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -123,15 +123,15 @@ public class MQTTHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
validMqtt = bridgeSettings.isValidMQTT();
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
validMqtt = bridgeSettings.getBridgeSettingsDescriptor().isValidMQTT();
|
||||
log.info("MQTT Home created." + (validMqtt ? "" : " No MQTT Clients configured."));
|
||||
if(validMqtt) {
|
||||
aGsonHandler =
|
||||
new GsonBuilder()
|
||||
.create();
|
||||
handlers = new HashMap<String, MQTTHandler>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getMqttaddress().getDevices().iterator();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getMqttaddress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aClientConfig = theList.next();
|
||||
MQTTHandler aHandler = new MQTTHandler(aClientConfig);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.bwssystems.HABridge.plugins.somfy;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
@@ -31,7 +31,7 @@ public class SomfyHome implements Home {
|
||||
private Map<String, SomfyInfo> somfys;
|
||||
private Boolean validSomfy;
|
||||
|
||||
public SomfyHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public SomfyHome(BridgeSettings bridgeSettings) {
|
||||
createHome(bridgeSettings);
|
||||
|
||||
}
|
||||
@@ -97,12 +97,12 @@ public class SomfyHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
validSomfy = bridgeSettings.isValidSomfy();
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
validSomfy = bridgeSettings.getBridgeSettingsDescriptor().isValidSomfy();
|
||||
log.info("Somfy Home created." + (validSomfy ? "" : " No Somfys configured."));
|
||||
if(validSomfy) {
|
||||
somfys = new HashMap<>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getSomfyAddress().getDevices().iterator();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getSomfyAddress().getDevices().iterator();
|
||||
while (theList.hasNext()) {
|
||||
NamedIP aSomfy = theList.next();
|
||||
somfys.put(aSomfy.getName(), new SomfyInfo(aSomfy, aSomfy.getName()));
|
||||
|
||||
@@ -15,22 +15,26 @@ import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
public class TCPHome implements Home {
|
||||
private static final Logger log = LoggerFactory.getLogger(TCPHome.class);
|
||||
private byte[] sendData;
|
||||
private Map<String, Socket> theSockets;
|
||||
private Gson aGsonHandler;
|
||||
|
||||
|
||||
public TCPHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public TCPHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -41,8 +45,12 @@ public class TCPHome implements Home {
|
||||
Socket dataSendSocket = null;
|
||||
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
|
||||
String theUrl = anItem.getItem().getAsString();
|
||||
if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("tcp://")) {
|
||||
String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
|
||||
|
||||
if(theUrl != null && !theUrl.isEmpty () && theUrl.contains("tcp://")) {
|
||||
if(!theUrl.startsWith("{\"tcpDevice\""))
|
||||
theUrl = "{\"tcpDevice\":\"" + theUrl + "\"}";
|
||||
TcpDevice theDevice = aGsonHandler.fromJson(theUrl, TcpDevice.class);
|
||||
String intermediate = theDevice.getTcpDevice().substring(theDevice.getTcpDevice().indexOf("://") + 3);
|
||||
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||
String hostAddr = null;
|
||||
@@ -58,14 +66,15 @@ public class TCPHome implements Home {
|
||||
try {
|
||||
IPAddress = InetAddress.getByName(hostAddr);
|
||||
} catch (UnknownHostException e) {
|
||||
// noop
|
||||
return aGsonHandler.toJson(HueErrorResponse.createResponse("901", null, "Cannot connect, Unknown Host", null, "/lights/" + device.getId(), null).getTheErrors());
|
||||
}
|
||||
|
||||
try {
|
||||
dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
||||
theSockets.put(hostPortion, dataSendSocket);
|
||||
if(theDevice.isPersistent())
|
||||
theSockets.put(hostPortion, dataSendSocket);
|
||||
} catch (Exception e) {
|
||||
// noop
|
||||
return aGsonHandler.toJson(HueErrorResponse.createResponse("901", null, "Cannot connect, Socket Creation issue", null, "/lights/" + device.getId(), null).getTheErrors());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,18 +89,32 @@ public class TCPHome implements Home {
|
||||
theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
|
||||
sendData = theUrlBody.getBytes();
|
||||
}
|
||||
|
||||
try {
|
||||
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
||||
outToClient.write(sendData);
|
||||
outToClient.flush();
|
||||
} catch (Exception e) {
|
||||
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
||||
outToClient.write(sendData);
|
||||
outToClient.flush();
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not send data to TCP socket <<<" + e.getMessage() + ">>>, closing socket: " + theUrl);
|
||||
try {
|
||||
dataSendSocket.close();
|
||||
} catch (IOException e1) {
|
||||
// noop
|
||||
}
|
||||
theSockets.remove(hostPortion);
|
||||
dataSendSocket = null;
|
||||
if(theDevice.isPersistent())
|
||||
theSockets.remove(hostPortion);
|
||||
return aGsonHandler.toJson(HueErrorResponse.createResponse("901", null, "Cannot send data", null, "/lights/" + device.getId(), null).getTheErrors());
|
||||
}
|
||||
|
||||
if(!theDevice.isPersistent()) {
|
||||
try {
|
||||
if(dataSendSocket != null)
|
||||
dataSendSocket.close();
|
||||
} catch (IOException e1) {
|
||||
// noop
|
||||
}
|
||||
dataSendSocket = null;
|
||||
}
|
||||
} else
|
||||
log.warn("Tcp Call to be presented as tcp://<ip_address>:<port>/payload, format of request unknown: " + theUrl);
|
||||
@@ -99,9 +122,10 @@ public class TCPHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
log.info("TCP Home created.");
|
||||
theSockets = new HashMap<String, Socket>();
|
||||
aGsonHandler = new GsonBuilder().create();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.bwssystems.HABridge.plugins.tcp;
|
||||
|
||||
public class TcpDevice {
|
||||
private String tcpDevice;
|
||||
private boolean persistent;
|
||||
public String getTcpDevice() {
|
||||
return tcpDevice;
|
||||
}
|
||||
public void setTcpDevice(String tcpDevice) {
|
||||
this.tcpDevice = tcpDevice;
|
||||
}
|
||||
public boolean isPersistent() {
|
||||
return persistent;
|
||||
}
|
||||
public void setPersistent(boolean persistent) {
|
||||
this.persistent = persistent;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.api.CallItem;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
@@ -25,7 +25,7 @@ public class UDPHome implements Home {
|
||||
private UDPDatagramSender theUDPDatagramSender;
|
||||
private byte[] sendData;
|
||||
|
||||
public UDPHome(BridgeSettingsDescriptor bridgeSettings, UDPDatagramSender aUDPDatagramSender) {
|
||||
public UDPHome(BridgeSettings bridgeSettings, UDPDatagramSender aUDPDatagramSender) {
|
||||
super();
|
||||
theUDPDatagramSender = aUDPDatagramSender;
|
||||
createHome(bridgeSettings);
|
||||
@@ -80,7 +80,7 @@ public class UDPHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
log.info("UDP Home created.");
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||
import com.bwssystems.HABridge.BridgeSettings;
|
||||
import com.bwssystems.HABridge.DeviceMapTypes;
|
||||
import com.bwssystems.HABridge.Home;
|
||||
import com.bwssystems.HABridge.NamedIP;
|
||||
@@ -25,7 +25,7 @@ public class VeraHome implements Home {
|
||||
private Map<String, VeraInfo> veras;
|
||||
private Boolean validVera;
|
||||
|
||||
public VeraHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
public VeraHome(BridgeSettings bridgeSettings) {
|
||||
super();
|
||||
createHome(bridgeSettings);
|
||||
}
|
||||
@@ -90,12 +90,12 @@ public class VeraHome implements Home {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||
validVera = bridgeSettings.isValidVera();
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
validVera = bridgeSettings.getBridgeSettingsDescriptor().isValidVera();
|
||||
log.info("Vera Home created." + (validVera ? "" : " No Veras configured."));
|
||||
if(validVera) {
|
||||
veras = new HashMap<String, VeraInfo>();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getVeraAddress().getDevices().iterator();
|
||||
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getVeraAddress().getDevices().iterator();
|
||||
while(theList.hasNext()) {
|
||||
NamedIP aVera = theList.next();
|
||||
veras.put(aVera.getName(), new VeraInfo(aVera));
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
[ng\:cloak],
|
||||
[ng-cloak],
|
||||
[data-ng-cloak],
|
||||
[x-ng-cloak],
|
||||
.ng-cloak,
|
||||
.x-ng-cloak {
|
||||
display: none !important;
|
||||
}
|
||||
body {
|
||||
padding-top: 60px;
|
||||
padding-bottom: 20px;
|
||||
@@ -8,4 +16,48 @@ body {
|
||||
}
|
||||
.sortorder.reverse:after {
|
||||
content: '\25bc';
|
||||
}
|
||||
}
|
||||
.form-container {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.form-container form > div {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.form-container form > button {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
legend.form-label {
|
||||
font-size: 24pt;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.form-control.error {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.form-hint {
|
||||
font-size: 10pt;
|
||||
line-height: 12pt;
|
||||
margin: -5px auto 5px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.form-hint.error {
|
||||
color: #C00;
|
||||
font-weight: bold;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
.msg-block {
|
||||
margin-top:5px;
|
||||
}
|
||||
.msg-error {
|
||||
color:#F00;
|
||||
font-size:14px;
|
||||
}
|
||||
11
src/main/resources/public/css/strength-meter.min.css
vendored
Normal file
11
src/main/resources/public/css/strength-meter.min.css
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* @copyright Copyright © Kartik Visweswaran, Krajee.com, 2015
|
||||
* @package yii2-password
|
||||
* @version 1.1.3
|
||||
*
|
||||
* Password Strength Meter
|
||||
* Modified and built for Yii Framework 2.0
|
||||
* Author: Kartik Visweswaran
|
||||
* Year: 2015
|
||||
* For more Yii related demos visit http://demos.krajee.com
|
||||
*/.kv-strength-container{width:100%;margin:0;padding:0;border:0}.kv-strength-container td{vertical-align:middle}.kv-meter-container{width:130px}.kv-meter{text-align:center}.kv-disabled{opacity:.65;cursor:not-allowed}.kv-scorebar-border{background:none repeat scroll 0 0 #333;border:1px solid #333;height:16px;width:100px;margin:0 auto;border-radius:4px}.kv-scorebar{background-image:url(../img/bg_strength_gradient.jpg);background-repeat:no-repeat;background-position:0 0;position:absolute;width:98px;height:14px;z-index:0;border-radius:2px}.kv-score{font-weight:700;font-size:75%;position:absolute;width:98px;z-index:10;border-radius:2px}.kv-score-0,.kv-score-1,.kv-score-5{color:#fff}.kv-score-2,.kv-score-3,.kv-score-4{color:#333}.kv-verdict{width:100%}
|
||||
BIN
src/main/resources/public/img/bg_strength_gradient.jpg
Normal file
BIN
src/main/resources/public/img/bg_strength_gradient.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 676 B |
@@ -13,6 +13,7 @@
|
||||
<link href="css/ngDialog.min.css" rel="stylesheet">
|
||||
<link href="css/ngDialog-theme-default.min.css" rel="stylesheet">
|
||||
<link href="css/scrollable-table.css" rel="stylesheet">
|
||||
<link href="css/strength-meter.min.css" rel="stylesheet">
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script type="text/javascript" src="js/html5shiv.min.js"></script>
|
||||
@@ -49,7 +50,7 @@
|
||||
<ul class="dropdown-menu" aria-labelledby="dLabel">
|
||||
<li><a href="http://www.bwssystems.com" target="_blank">Developed by BWS Systems</a></li>
|
||||
<li><a href="http://www.amazon.com/echo" target="_blank">Amazon Echo</a></li>
|
||||
<li><a href="">HA Bridge Version {{bridge.habridgeversion}}</a></li>
|
||||
<li><a href="">HA Bridge Version {{bridge.habridgeversion.version}}</a></li>
|
||||
<li><center>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
@@ -62,12 +63,13 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#!/login">Login/Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div ng-view>
|
||||
<div ng-view prerender-action="authorized()">
|
||||
|
||||
|
||||
</div>
|
||||
@@ -81,6 +83,10 @@
|
||||
<script src="js/rzslider.min.js"></script>
|
||||
<script src="js/ngDialog.min.js"></script>
|
||||
<script src="js/angular-scrollable-table.min.js"></script>
|
||||
<script src="js/strength-meter.min.js"></script>
|
||||
<script src="js/angular-base64.min.js"></script>
|
||||
<script src="js/angular-resource.min.js"></script>
|
||||
<script src="js/ngStorage.min.js"></script>
|
||||
<script src="scripts/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1
src/main/resources/public/js/angular-base64.min.js
vendored
Normal file
1
src/main/resources/public/js/angular-base64.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(){"use strict";angular.module("base64",[]).constant("$base64",function(){function a(a,b){var c=f.indexOf(a.charAt(b));if(-1==c)throw"Cannot decode base64";return c}function b(b){b=""+b;var c,d,f,g=b.length;if(0==g)return b;if(0!=g%4)throw"Cannot decode base64";c=0,b.charAt(g-1)==e&&(c=1,b.charAt(g-2)==e&&(c=2),g-=4);var h=[];for(d=0;g>d;d+=4)f=a(b,d)<<18|a(b,d+1)<<12|a(b,d+2)<<6|a(b,d+3),h.push(String.fromCharCode(f>>16,255&f>>8,255&f));switch(c){case 1:f=a(b,d)<<18|a(b,d+1)<<12|a(b,d+2)<<6,h.push(String.fromCharCode(f>>16,255&f>>8));break;case 2:f=a(b,d)<<18|a(b,d+1)<<12,h.push(String.fromCharCode(f>>16))}return h.join("")}function c(a,b){var c=a.charCodeAt(b);if(c>255)throw"INVALID_CHARACTER_ERR: DOM Exception 5";return c}function d(a){if(1!=arguments.length)throw"SyntaxError: Not enough arguments";var b,d,g=[];a=""+a;var h=a.length-a.length%3;if(0==a.length)return a;for(b=0;h>b;b+=3)d=c(a,b)<<16|c(a,b+1)<<8|c(a,b+2),g.push(f.charAt(d>>18)),g.push(f.charAt(63&d>>12)),g.push(f.charAt(63&d>>6)),g.push(f.charAt(63&d));switch(a.length-h){case 1:d=c(a,b)<<16,g.push(f.charAt(d>>18)+f.charAt(63&d>>12)+e+e);break;case 2:d=c(a,b)<<16|c(a,b+1)<<8,g.push(f.charAt(d>>18)+f.charAt(63&d>>12)+f.charAt(63&d>>6)+e)}return g.join("")}var e="=",f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";return{encode:d,decode:b}}())}();
|
||||
15
src/main/resources/public/js/angular-resource.min.js
vendored
Normal file
15
src/main/resources/public/js/angular-resource.min.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
AngularJS v1.6.1
|
||||
(c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(W,b){'use strict';function K(q,g){g=g||{};b.forEach(g,function(b,h){delete g[h]});for(var h in q)!q.hasOwnProperty(h)||"$"===h.charAt(0)&&"$"===h.charAt(1)||(g[h]=q[h]);return g}var B=b.$$minErr("$resource"),Q=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;b.module("ngResource",["ng"]).provider("$resource",function(){var q=/^https?:\/\/\[[^\]]*][^/]*/,g=this;this.defaults={stripTrailingSlashes:!0,cancellable:!1,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},
|
||||
"delete":{method:"DELETE"}}};this.$get=["$http","$log","$q","$timeout",function(h,P,L,M){function C(b,e){this.template=b;this.defaults=p({},g.defaults,e);this.urlParams={}}function x(D,e,u,m){function c(a,d){var c={};d=p({},e,d);t(d,function(d,l){y(d)&&(d=d(a));var f;if(d&&d.charAt&&"@"===d.charAt(0)){f=a;var k=d.substr(1);if(null==k||""===k||"hasOwnProperty"===k||!Q.test("."+k))throw B("badmember",k);for(var k=k.split("."),e=0,g=k.length;e<g&&b.isDefined(f);e++){var h=k[e];f=null!==f?f[h]:void 0}}else f=
|
||||
d;c[l]=f});return c}function R(a){return a.resource}function l(a){K(a||{},this)}var q=new C(D,m);u=p({},g.defaults.actions,u);l.prototype.toJSON=function(){var a=p({},this);delete a.$promise;delete a.$resolved;return a};t(u,function(a,d){var b=/^(POST|PUT|PATCH)$/i.test(a.method),e=a.timeout,g=N(a.cancellable)?a.cancellable:q.defaults.cancellable;e&&!S(e)&&(P.debug("ngResource:\n Only numeric values are allowed as `timeout`.\n Promises are not supported in $resource, because the same value would be used for multiple requests. If you are looking for a way to cancel requests, you should use the `cancellable` option."),
|
||||
delete a.timeout,e=null);l[d]=function(f,k,m,D){function u(a){r.catch(E);z.resolve(a)}var G={},v,w,A;switch(arguments.length){case 4:A=D,w=m;case 3:case 2:if(y(k)){if(y(f)){w=f;A=k;break}w=k;A=m}else{G=f;v=k;w=m;break}case 1:y(f)?w=f:b?v=f:G=f;break;case 0:break;default:throw B("badargs",arguments.length);}var F=this instanceof l,n=F?v:a.isArray?[]:new l(v),s={},C=a.interceptor&&a.interceptor.response||R,x=a.interceptor&&a.interceptor.responseError||void 0,H=!!A,I=!!x,z,J;t(a,function(a,d){switch(d){default:s[d]=
|
||||
T(a);case "params":case "isArray":case "interceptor":case "cancellable":}});!F&&g&&(z=L.defer(),s.timeout=z.promise,e&&(J=M(z.resolve,e)));b&&(s.data=v);q.setUrlParams(s,p({},c(v,a.params||{}),G),a.url);var r=h(s).then(function(f){var c=f.data;if(c){if(O(c)!==!!a.isArray)throw B("badcfg",d,a.isArray?"array":"object",O(c)?"array":"object",s.method,s.url);if(a.isArray)n.length=0,t(c,function(a){"object"===typeof a?n.push(new l(a)):n.push(a)});else{var b=n.$promise;K(c,n);n.$promise=b}}f.resource=n;
|
||||
return f}),r=r["finally"](function(){n.$resolved=!0;!F&&g&&(n.$cancelRequest=E,M.cancel(J),z=J=s.timeout=null)}),r=r.then(function(a){var d=C(a);(w||E)(d,a.headers,a.status,a.statusText);return d},H||I?function(a){H&&A(a);return I?x(a):L.reject(a)}:void 0);H&&!I&&r.catch(E);return F?r:(n.$promise=r,n.$resolved=!1,g&&(n.$cancelRequest=u),n)};l.prototype["$"+d]=function(a,c,b){y(a)&&(b=c,c=a,a={});a=l[d].call(this,a,this,c,b);return a.$promise||a}});l.bind=function(a){a=p({},e,a);return x(D,a,u,m)};
|
||||
return l}var E=b.noop,t=b.forEach,p=b.extend,T=b.copy,O=b.isArray,N=b.isDefined,y=b.isFunction,S=b.isNumber,U=b.$$encodeUriQuery,V=b.$$encodeUriSegment;C.prototype={setUrlParams:function(b,e,g){var m=this,c=g||m.template,h,l,p="",a=m.urlParams=Object.create(null);t(c.split(/\W/),function(d){if("hasOwnProperty"===d)throw B("badname");!/^\d+$/.test(d)&&d&&(new RegExp("(^|[^\\\\]):"+d+"(\\W|$)")).test(c)&&(a[d]={isQueryParamValue:(new RegExp("\\?.*=:"+d+"(?:\\W|$)")).test(c)})});c=c.replace(/\\:/g,":");
|
||||
c=c.replace(q,function(a){p=a;return""});e=e||{};t(m.urlParams,function(a,b){h=e.hasOwnProperty(b)?e[b]:m.defaults[b];N(h)&&null!==h?(l=a.isQueryParamValue?U(h,!0):V(h),c=c.replace(new RegExp(":"+b+"(\\W|$)","g"),function(a,b){return l+b})):c=c.replace(new RegExp("(/?):"+b+"(\\W|$)","g"),function(a,b,d){return"/"===d.charAt(0)?d:b+d})});m.defaults.stripTrailingSlashes&&(c=c.replace(/\/+$/,"")||"/");c=c.replace(/\/\.(?=\w+($|\?))/,".");b.url=p+c.replace(/\/\\\./,"/.");t(e,function(a,c){m.urlParams[c]||
|
||||
(b.params=b.params||{},b.params[c]=a)})}};return x}]})})(window,window.angular);
|
||||
//# sourceMappingURL=angular-resource.min.js.map
|
||||
8
src/main/resources/public/js/angular-resource.min.js.map
Normal file
8
src/main/resources/public/js/angular-resource.min.js.map
Normal file
File diff suppressed because one or more lines are too long
1
src/main/resources/public/js/ngStorage.min.js
vendored
Normal file
1
src/main/resources/public/js/ngStorage.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/*! ngstorage 0.3.10 | Copyright (c) 2016 Gias Kay Lee | MIT License */!function(a,b){"use strict";"function"==typeof define&&define.amd?define(["angular"],b):a.hasOwnProperty("angular")?b(a.angular):"object"==typeof exports&&(module.exports=b(require("angular")))}(this,function(a){"use strict";function b(a,b){var c;try{c=a[b]}catch(d){c=!1}if(c){var e="__"+Math.round(1e7*Math.random());try{a[b].setItem(e,e),a[b].removeItem(e,e)}catch(d){c=!1}}return c}function c(c){var d=b(window,c);return function(){var e="ngStorage-";this.setKeyPrefix=function(a){if("string"!=typeof a)throw new TypeError("[ngStorage] - "+c+"Provider.setKeyPrefix() expects a String.");e=a};var f=a.toJson,g=a.fromJson;this.setSerializer=function(a){if("function"!=typeof a)throw new TypeError("[ngStorage] - "+c+"Provider.setSerializer expects a function.");f=a},this.setDeserializer=function(a){if("function"!=typeof a)throw new TypeError("[ngStorage] - "+c+"Provider.setDeserializer expects a function.");g=a},this.supported=function(){return!!d},this.get=function(a){return d&&g(d.getItem(e+a))},this.set=function(a,b){return d&&d.setItem(e+a,f(b))},this.remove=function(a){d&&d.removeItem(e+a)},this.$get=["$rootScope","$window","$log","$timeout","$document",function(d,h,i,j,k){var l,m,n=e.length,o=b(h,c),p=o||(i.warn("This browser does not support Web Storage!"),{setItem:a.noop,getItem:a.noop,removeItem:a.noop}),q={$default:function(b){for(var c in b)a.isDefined(q[c])||(q[c]=a.copy(b[c]));return q.$sync(),q},$reset:function(a){for(var b in q)"$"===b[0]||delete q[b]&&p.removeItem(e+b);return q.$default(a)},$sync:function(){for(var a,b=0,c=p.length;c>b;b++)(a=p.key(b))&&e===a.slice(0,n)&&(q[a.slice(n)]=g(p.getItem(a)))},$apply:function(){var b;if(m=null,!a.equals(q,l)){b=a.copy(l),a.forEach(q,function(c,d){a.isDefined(c)&&"$"!==d[0]&&(p.setItem(e+d,f(c)),delete b[d])});for(var c in b)p.removeItem(e+c);l=a.copy(q)}},$supported:function(){return!!o}};return q.$sync(),l=a.copy(q),d.$watch(function(){m||(m=j(q.$apply,100,!1))}),h.addEventListener&&h.addEventListener("storage",function(b){if(b.key){var c=k[0];c.hasFocus&&c.hasFocus()||e!==b.key.slice(0,n)||(b.newValue?q[b.key.slice(n)]=g(b.newValue):delete q[b.key.slice(n)],l=a.copy(q),d.$apply())}}),h.addEventListener&&h.addEventListener("beforeunload",function(){q.$apply()}),q}]}}return a=a&&a.module?a:window.angular,a.module("ngStorage",[]).provider("$localStorage",c("localStorage")).provider("$sessionStorage",c("sessionStorage"))});
|
||||
8
src/main/resources/public/js/strength-meter.min.js
vendored
Normal file
8
src/main/resources/public/js/strength-meter.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@
|
||||
|
||||
<p>
|
||||
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
|
||||
<button ng-if="bridge.securityInfo.useLinkButton" class="btn btn-primary" type="submit" ng-click="pushLinkButton()">Link</button>
|
||||
</p>
|
||||
<scrollable-table watch="bridge.devices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
|
||||
29
src/main/resources/public/views/login.html
Normal file
29
src/main/resources/public/views/login.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Login</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div ng-if="!loggedIn" class="form-container">
|
||||
|
||||
<form name="loginForm" role="form" ng-submit="login(username, password)">
|
||||
<legend class="form-label">Enter Credentials</legend>
|
||||
<div class="form-group">
|
||||
<label>User</label> <input id="username" name="username"
|
||||
class="form-control" type="text" ng-model="username"
|
||||
placeholder="someone" autofocus/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password</label> <input id="password" name="password"
|
||||
class="form-control" type="password" ng-model="password" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-success" value="Submit">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div ng-if="loggedIn">
|
||||
<button type="button" class="btn btn-danger" ng-click="logout()">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
51
src/main/resources/public/views/securitydialog.html
Normal file
51
src/main/resources/public/views/securitydialog.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<div class="form-container ngdialog-message" ng-controller="SecurityDialogCtrl">
|
||||
|
||||
<form name="securityForm" role="form">
|
||||
<legend class="form-label">Update Security Settings</legend>
|
||||
<div class="form-group">
|
||||
<label>Use Link Button</label>
|
||||
<input type="checkbox"
|
||||
ng-model="useLinkButton" ng-true-value=true
|
||||
ng-false-value=false /> {{useLinkButton}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Use username/password for HUE Api</label>
|
||||
<input type="checkbox"
|
||||
ng-model="secureHueApi" ng-true-value=true
|
||||
ng-false-value=false /> {{secureHueApi}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-primary" ng-click="setSecurityInfo()">Update</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Add/Delete User</label>
|
||||
<input id="new-user" name="new-user" class="form-control"
|
||||
type="text" ng-model="newUser"
|
||||
placeholder="someone" nu-check="new-user" />
|
||||
</div>
|
||||
<div ng-if="isSecure" class="form-group">
|
||||
<button type="button" class="btn btn-danger" ng-click="delUser(newUser)">Delete</button>
|
||||
</div>
|
||||
<div ng-if="showPassword" postrender-action="setBlankPassword('password-1')">
|
||||
<div class="form-group">
|
||||
<label>Change Password for {{username}}</label>
|
||||
<input id="password-1" name="password-1" type="password" class="form-control strength" ng-model="password" data-toggle-title="Display Password" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Confirm Password</label>
|
||||
<input id="password-2" name="password-2" class="form-control" type="password" ng-model="password2" pw-check="password-1" />
|
||||
<div class="msg-block" ng-show="securityForm.$error">
|
||||
<span class="msg-error" ng-show="securityForm.$error.pwmatch">Passwords don't match.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="matched" class="form-group">
|
||||
<button ng-if="!addingUser" class="btn btn-warning" ng-click="changePassword(password, password2)">Change Password</button>
|
||||
<button ng-if="addingUser" class="btn btn-success" ng-click="addUser(newUser, password, password2)">Add User</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-success" ng-click="dismissDialog()" autofocus>Dismiss</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -48,16 +48,11 @@
|
||||
<button ng-disabled="bridge.isInControl"
|
||||
class="btn btn-success" type="submit" ng-click="saveSettings()">Save</button>
|
||||
<button ng-disabled="bridge.isInControl" class="btn btn-warning"
|
||||
type="submit" ng-click="bridgeReinit()">Bridge
|
||||
Reinitialize</button>
|
||||
type="submit" ng-click="bridgeReinit()">Bridge Reinitialize</button>
|
||||
<button ng-disabled="bridge.isInControl" class="btn btn-danger"
|
||||
type="submit" ng-click="bridgeStop()">Bridge Stop</button>
|
||||
<button class="btn btn-primary" type="submit" onclick="myRefresh()">Refresh</button>
|
||||
<script>
|
||||
function myRefresh() {
|
||||
location.reload();
|
||||
}
|
||||
</script>
|
||||
<button class="btn btn-warning"
|
||||
type="submit" ng-click="changeSeuritySettings()">Update Security Settings</button>
|
||||
</p>
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.bwssystems.hass.test;
|
||||
package com.bwssystems.domoticz.test;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.bwssystems.hass.test;
|
||||
package com.bwssystems.domoticz.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
Reference in New Issue
Block a user