mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 16:17:30 +00:00
Compare commits
19 Commits
v4.3.0
...
v4.5.0alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50af884563 | ||
|
|
0737c54a0e | ||
|
|
a7e516925c | ||
|
|
2f1adf9d4b | ||
|
|
cd5417c2e0 | ||
|
|
ba621fcb85 | ||
|
|
7442b0d0ca | ||
|
|
c275926117 | ||
|
|
895a9ec99b | ||
|
|
6dfd70dfee | ||
|
|
0bdb321fd7 | ||
|
|
b508a8a16a | ||
|
|
ddee3a42a9 | ||
|
|
b000215b26 | ||
|
|
a2b652907f | ||
|
|
6bf1bbc8a8 | ||
|
|
1a402e425e | ||
|
|
59ef6e88de | ||
|
|
7d4f953c89 |
27
README.md
27
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.0.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.0.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.0/ha-bridge-4.3.0.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.0.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.0/ha-bridge-4.3.0.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.0.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.0.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,11 @@ 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>`
|
||||
The default security key is encoded into the Java code. This should not be used as anyone with access to the code can decode your passworsd. To override what 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 haced. The command line example:
|
||||
```
|
||||
java -jar -Dsecurity.key=Xfawer354WertSdf321234asd ha-bridge-W.X.Y.jar
|
||||
```
|
||||
## 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.
|
||||
@@ -226,6 +231,8 @@ This is where all of the configuration occurs for what ports and IP's the bridge
|
||||
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.
|
||||
#### 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 +314,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.0</version>
|
||||
<version>4.5.0alpha-4</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;
|
||||
}
|
||||
}
|
||||
|
||||
263
src/main/java/com/bwssystems/HABridge/BridgeSecurity.java
Normal file
263
src/main/java/com/bwssystems/HABridge/BridgeSecurity.java
Normal file
@@ -0,0 +1,263 @@
|
||||
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 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.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 byte[] SALT = {
|
||||
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||
};
|
||||
private char[] habridgeKey;
|
||||
private BridgeSecurityDescriptor securityDescriptor;
|
||||
private boolean settingsChanged;
|
||||
|
||||
public BridgeSecurity(char[] theKey) {
|
||||
habridgeKey = theKey;
|
||||
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();
|
||||
}
|
||||
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 void setExecGarden(String theGarden) {
|
||||
securityDescriptor.setExecGarden(theGarden);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
public String getExecGarden() {
|
||||
return securityDescriptor.getExecGarden();
|
||||
}
|
||||
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.setExecGarden(getExecGarden());
|
||||
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;
|
||||
}
|
||||
|
||||
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,62 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BridgeSecurityDescriptor {
|
||||
private Map<String, User> users;
|
||||
private boolean useLinkButton;
|
||||
private String execGarden;
|
||||
private boolean secureHueApi;
|
||||
|
||||
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 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,7 @@ 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.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -26,12 +28,18 @@ public class BridgeSettings extends BackupHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||
private BridgeSettingsDescriptor theBridgeSettings;
|
||||
private BridgeControlDescriptor bridgeControl;
|
||||
private BridgeSecurity bridgeSecurity;
|
||||
|
||||
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";
|
||||
bridgeSecurity = new BridgeSecurity(theKey.toCharArray());
|
||||
String ipV6Stack = System.getProperty("ipV6Stack");
|
||||
if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) {
|
||||
System.setProperty("java.net.preferIPv4Stack" , "true");
|
||||
}
|
||||
@@ -43,6 +51,9 @@ public class BridgeSettings extends BackupHandler {
|
||||
public BridgeSettingsDescriptor getBridgeSettingsDescriptor() {
|
||||
return theBridgeSettings;
|
||||
}
|
||||
public BridgeSecurity getBridgeSecurity() {
|
||||
return bridgeSecurity;
|
||||
}
|
||||
public void buildSettings() {
|
||||
String addressString = null;
|
||||
String theVeraAddress = null;
|
||||
@@ -175,6 +186,8 @@ public class BridgeSettings extends BackupHandler {
|
||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||
|
||||
setupInternalTestUser();
|
||||
|
||||
bridgeSecurity.setSecurityData(theBridgeSettings.getSecurityData());
|
||||
}
|
||||
|
||||
public void loadConfig() {
|
||||
@@ -203,6 +216,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) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (GeneralSecurityException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
bridgeSecurity.setSettingsChanged(false);
|
||||
}
|
||||
String jsonValue = aRenderer.render(newBridgeSettings);
|
||||
configWriter(jsonValue, configPath);
|
||||
_loadConfig(configPath);
|
||||
@@ -219,7 +244,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -249,7 +274,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");
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ public class BridgeSettingsDescriptor {
|
||||
private boolean domoticzconfigured;
|
||||
private IpList somfyaddress;
|
||||
private boolean somfyconfigured;
|
||||
|
||||
private boolean lifxconfigured;
|
||||
private String securityData;
|
||||
|
||||
public BridgeSettingsDescriptor() {
|
||||
super();
|
||||
@@ -295,6 +295,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;
|
||||
@@ -435,11 +441,14 @@ public class BridgeSettingsDescriptor {
|
||||
|
||||
public void setupInternalTestUser() {
|
||||
boolean found = false;
|
||||
for (String key : whitelist.keySet()) {
|
||||
if(key.equals(DEFAULT_INTERNAL_USER))
|
||||
found = true;
|
||||
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,8 +92,15 @@ 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
33
src/main/java/com/bwssystems/HABridge/SecurityInfo.java
Normal file
33
src/main/java/com/bwssystems/HABridge/SecurityInfo.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.bwssystems.HABridge;
|
||||
|
||||
public class SecurityInfo {
|
||||
private boolean useLinkButton;
|
||||
private String execGarden;
|
||||
private boolean secureHueApi;
|
||||
private boolean isSecure;
|
||||
|
||||
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 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,36 @@ 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() + "\"}";
|
||||
response.type("application/json");
|
||||
return "{\"version\":\"" + version.getVersion() + "\",\"isSecure\":" + bridgeSettings.getBridgeSecurity().isSecure() + "}";
|
||||
});
|
||||
|
||||
// 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) -> {
|
||||
get (SYSTEM_CONTEXT + "/habridge/testuser", (request, response) -> {
|
||||
log.debug("Get HA Bridge testuser: " + bridgeSettings.getBridgeSettingsDescriptor().getInternalTestUser());
|
||||
response.status(HttpStatus.SC_OK);
|
||||
response.type("application/json");
|
||||
return "{\"user\":\"" + bridgeSettings.getBridgeSettingsDescriptor().getInternalTestUser() + "\"}";
|
||||
});
|
||||
|
||||
// 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 +109,192 @@ 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);
|
||||
if(theInfo.getExecGarden() != null)
|
||||
bridgeSettings.getBridgeSecurity().setExecGarden(theInfo.getExecGarden());
|
||||
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 +303,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 +333,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 +352,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 +368,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 +391,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 +410,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 +431,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 +440,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,7 +595,7 @@ 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 = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors != null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
@@ -590,7 +609,7 @@ 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 = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
@@ -607,7 +626,7 @@ 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 = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
@@ -632,7 +651,7 @@ 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 = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||
if (theErrors == null) {
|
||||
if(bridgeSettings.isSettingsChanged())
|
||||
bridgeSettingMaster.updateConfigFile();
|
||||
@@ -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 = 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 + "\"}}]";
|
||||
}
|
||||
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 (bridgeSettings.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 = bridgeSettings.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 = bridgeSettings.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 = bridgeSettings.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 = bridgeSettings.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,15 @@ 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();
|
||||
execGarden = execGarden.trim();
|
||||
if(execGarden != null && !execGarden.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 +59,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 +75,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,55 @@ 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;
|
||||
}
|
||||
|
||||
.password-count {
|
||||
float: right;
|
||||
position: relative;
|
||||
bottom: 24px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.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
@@ -1,69 +1,124 @@
|
||||
var app = angular.module ('habridge', ['ngRoute', 'ngToast', 'rzModule', 'ngDialog', 'scrollable-table']);
|
||||
var app = angular.module ('habridge', ['ngRoute', 'ngToast', 'rzModule', 'ngDialog', 'base64', 'scrollable-table', 'ngResource', 'ngStorage']);
|
||||
|
||||
app.config (function ($locationProvider, $routeProvider) {
|
||||
$locationProvider.hashPrefix('!');
|
||||
|
||||
$routeProvider.when ('/', {
|
||||
templateUrl: 'views/configuration.html',
|
||||
controller: 'ViewingController'
|
||||
controller: 'ViewingController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/system', {
|
||||
templateUrl: 'views/system.html',
|
||||
controller: 'SystemController'
|
||||
controller: 'SystemController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/logs', {
|
||||
templateUrl: 'views/logs.html',
|
||||
controller: 'LogsController'
|
||||
controller: 'LogsController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/editdevice', {
|
||||
templateUrl: 'views/editdevice.html',
|
||||
controller: 'EditController'
|
||||
controller: 'EditController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/veradevices', {
|
||||
templateUrl: 'views/veradevice.html',
|
||||
controller: 'VeraController'
|
||||
controller: 'VeraController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/verascenes', {
|
||||
templateUrl: 'views/verascene.html',
|
||||
controller: 'VeraController'
|
||||
controller: 'VeraController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/harmonydevices', {
|
||||
templateUrl: 'views/harmonydevice.html',
|
||||
controller: 'HarmonyController'
|
||||
controller: 'HarmonyController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/harmonyactivities', {
|
||||
templateUrl: 'views/harmonyactivity.html',
|
||||
controller: 'HarmonyController'
|
||||
controller: 'HarmonyController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/nest', {
|
||||
templateUrl: 'views/nestactions.html',
|
||||
controller: 'NestController'
|
||||
controller: 'NestController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/huedevices', {
|
||||
templateUrl: 'views/huedevice.html',
|
||||
controller: 'HueController'
|
||||
controller: 'HueController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/haldevices', {
|
||||
templateUrl: 'views/haldevice.html',
|
||||
controller: 'HalController'
|
||||
controller: 'HalController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/mqttmessages', {
|
||||
templateUrl: 'views/mqttpublish.html',
|
||||
controller: 'MQTTController'
|
||||
controller: 'MQTTController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/hassdevices', {
|
||||
templateUrl: 'views/hassdevice.html',
|
||||
controller: 'HassController'
|
||||
controller: 'HassController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/domoticzdevices', {
|
||||
templateUrl: 'views/domoticzdevice.html',
|
||||
controller: 'DomoticzController'
|
||||
controller: 'DomoticzController',
|
||||
requiresAuthentication: true
|
||||
}).when('/somfydevices', {
|
||||
templateUrl: 'views/somfydevice.html',
|
||||
controller: 'SomfyController'
|
||||
}).otherwise ({
|
||||
controller: 'DomoticzController'
|
||||
templateUrl: 'views/somfydevice.html',
|
||||
controller: 'SomfyController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/lifxdevices', {
|
||||
templateUrl: 'views/lifxdevice.html',
|
||||
controller: 'LifxController'
|
||||
controller: 'LifxController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/login', {
|
||||
templateUrl: 'views/login.html',
|
||||
controller: 'LoginController'
|
||||
}).otherwise ({
|
||||
templateUrl: 'views/configuration.html',
|
||||
controller: 'ViewingController'
|
||||
controller: 'ViewingController',
|
||||
requiresAuthentication: true
|
||||
})
|
||||
});
|
||||
|
||||
app.run( function (bridgeService) {
|
||||
bridgeService.loadBridgeSettings();
|
||||
app.run( async function ($rootScope, $location, Auth, bridgeService) {
|
||||
bridgeService.getHABridgeVersion();
|
||||
bridgeService.getTestUser();
|
||||
bridgeService.viewMapTypes();
|
||||
|
||||
$rootScope.$on('securitySetupReceived', function(event, data) {
|
||||
Auth.init();
|
||||
if(Auth.isLoggedIn()) {
|
||||
bridgeService.loadBridgeSettings();
|
||||
bridgeService.getTestUser();
|
||||
bridgeService.getSecurityInfo();
|
||||
bridgeService.viewMapTypes();
|
||||
$location.path("/");
|
||||
} else {
|
||||
event.preventDefault();
|
||||
$location.path("/login");
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('securityReview', function(event, data) {
|
||||
if(Auth.isLoggedIn()) {
|
||||
$location.path("/");
|
||||
} else {
|
||||
event.preventDefault();
|
||||
$location.path("/login");
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('securityReinit', function(event, data) {
|
||||
event.preventDefault();
|
||||
Auth.logout();
|
||||
$location.path("/login");
|
||||
});
|
||||
|
||||
$rootScope.$on('$routeChangeStart', function (event, next) {
|
||||
if (!Auth.checkPermissionForView(next)){
|
||||
event.preventDefault();
|
||||
$location.path("/login");
|
||||
} else {
|
||||
$location.path(next.originalPath);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
String.prototype.replaceAll = function (search, replace)
|
||||
@@ -78,9 +133,12 @@ String.prototype.replaceAll = function (search, replace)
|
||||
};
|
||||
|
||||
|
||||
app.service ('bridgeService', function ($http, $window, ngToast) {
|
||||
app.service ('bridgeService', function ($rootScope, $http, $base64, $location, ngToast) {
|
||||
var self = this;
|
||||
this.state = {base: "./api/devices", bridgelocation: ".", systemsbase: "./system", huebase: "./api", configs: [], backups: [], devices: [], device: {}, mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], mapTypes: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false, showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: "", viewDevId: "", queueDevId: ""};
|
||||
this.state = {base: "./api/devices", bridgelocation: ".", systemsbase: "./system", huebase: "./api", configs: [], backups: [], devices: [], device: {},
|
||||
mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], mapTypes: [], olddevicename: "", logShowAll: false,
|
||||
isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false,
|
||||
showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: {}, viewDevId: "", queueDevId: "", securityInfo: {}};
|
||||
|
||||
this.displayWarn = function(errorTitle, error) {
|
||||
var toastContent = errorTitle;
|
||||
@@ -122,6 +180,14 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
||||
content: theTitle});
|
||||
};
|
||||
|
||||
this.displayTimer = function (theTitle, timeMillis) {
|
||||
ngToast.create({
|
||||
className: "success",
|
||||
timeout: timeMillis,
|
||||
dismissOnClick: false,
|
||||
content: theTitle + " in " + timeMillis/1000 + " seconds"});
|
||||
};
|
||||
|
||||
this.viewDevices = function () {
|
||||
return $http.get(this.state.base).then(
|
||||
function (response) {
|
||||
@@ -158,7 +224,11 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
||||
this.getHABridgeVersion = function () {
|
||||
return $http.get(this.state.systemsbase + "/habridge/version").then(
|
||||
function (response) {
|
||||
self.state.habridgeversion = response.data.version;
|
||||
self.state.habridgeversion = {
|
||||
version: response.data.version,
|
||||
isSecure: response.data.isSecure
|
||||
};
|
||||
$rootScope.$broadcast('securitySetupReceived', 'done');
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Cannot get version: ", error);
|
||||
@@ -177,6 +247,110 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
||||
);
|
||||
};
|
||||
|
||||
this.getSecurityInfo = function () {
|
||||
return $http.get(this.state.systemsbase + "/securityinfo").then(
|
||||
function (response) {
|
||||
self.state.securityInfo = response.data;
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Cannot get security info: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.changeSecuritySettings = function (useLinkButton, secureHueApi, execGarden) {
|
||||
var newSecurityInfo = {};
|
||||
newSecurityInfo = {
|
||||
useLinkButton: useLinkButton,
|
||||
secureHueApi: secureHueApi,
|
||||
execGarden: execGarden
|
||||
};
|
||||
return $http.post(this.state.systemsbase + "/changesecurityinfo", newSecurityInfo ).then(
|
||||
function (response) {
|
||||
self.state.securityInfo = response.data;
|
||||
self.displaySuccess("Updated security settings.")
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Update ecurity settings Error: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.isSecure = function () {
|
||||
if(self.state.habridgeversion === undefined)
|
||||
return true;
|
||||
if(self.state.habridgeversion.isSecure === undefined)
|
||||
return true;
|
||||
|
||||
return self.state.habridgeversion.isSecure;
|
||||
};
|
||||
|
||||
this.changePassword = function (aPassword, aPassword2) {
|
||||
var newUserInfo = {};
|
||||
newUserInfo = {
|
||||
username: self.state.loggedInUser,
|
||||
password: aPassword,
|
||||
password2: aPassword2
|
||||
};
|
||||
var theEncodedPayload = $base64.encode(angular.toJson(newUserInfo));
|
||||
return $http.post(this.state.systemsbase + "/setpassword", theEncodedPayload ).then(
|
||||
function (response) {
|
||||
self.displaySuccess("Password updated")
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Update password Error: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.addUser = function (username, aPassword, aPassword2) {
|
||||
var newUserInfo = {};
|
||||
newUserInfo = {
|
||||
username: username,
|
||||
password: aPassword,
|
||||
password2: aPassword2
|
||||
};
|
||||
var theEncodedPayload = $base64.encode(angular.toJson(newUserInfo));
|
||||
return $http.put(this.state.systemsbase + "/adduser", theEncodedPayload ).then(
|
||||
function (response) {
|
||||
self.displaySuccess("User added")
|
||||
if(!self.isSecure()) {
|
||||
self.getHABridgeVersion();
|
||||
}
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("User add Error: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.delUser = function (username) {
|
||||
var newUserInfo = {};
|
||||
newUserInfo = {
|
||||
username: username
|
||||
};
|
||||
var theEncodedPayload = $base64.encode(angular.toJson(newUserInfo));
|
||||
return $http.put(this.state.systemsbase + "/deluser", theEncodedPayload ).then(
|
||||
function (response) {
|
||||
self.displaySuccess("User deleted")
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("User add Error: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.pushLinkButton = function () {
|
||||
return $http.put(this.state.systemsbase + "/presslinkbutton").then(
|
||||
function (response) {
|
||||
self.displayTimer("Link your device", 30000);
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Cannot get security info: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.aContainsB = function (a, b) {
|
||||
return a.indexOf(b) >= 0;
|
||||
}
|
||||
@@ -705,10 +879,9 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
||||
return $http.get(this.state.bridgelocation + "/description.xml").then(
|
||||
function (response) {
|
||||
ngToast.dismiss(self.state.myToastMsg);
|
||||
self.viewConfigs();
|
||||
self.state.myToastMsg = null;
|
||||
self.state.isInControl = false;
|
||||
window.location.reload();
|
||||
$rootScope.$broadcast('securityReinit', 'done');
|
||||
},
|
||||
function (error) {
|
||||
setTimeout(function(){
|
||||
@@ -949,7 +1122,7 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
|
||||
};
|
||||
});
|
||||
|
||||
app.controller ('SystemController', function ($scope, $location, $http, $window, bridgeService) {
|
||||
app.controller ('SystemController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
bridgeService.viewConfigs();
|
||||
bridgeService.loadBridgeSettings();
|
||||
$scope.bridge = bridgeService.state;
|
||||
@@ -1122,9 +1295,117 @@ app.controller ('SystemController', function ($scope, $location, $http, $window,
|
||||
else
|
||||
$scope.imgUrl = "glyphicon glyphicon-plus";
|
||||
};
|
||||
|
||||
$scope.changeSeuritySettings = function () {
|
||||
bridgeService.getSecurityInfo();
|
||||
ngDialog.open({
|
||||
template: 'views/securitydialog.html',
|
||||
controller: 'SecurityDialogCtrl',
|
||||
className: 'ngdialog-theme-default'
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('LogsController', function ($scope, $location, $http, $window, bridgeService) {
|
||||
app.directive('nuCheck', [function () {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function (scope, elem, attrs, ctrl) {
|
||||
var newUser = '#' + attrs.nuCheck;
|
||||
elem.add(newUser).on('keyup', function () {
|
||||
scope.$apply(function () {
|
||||
if($(newUser).val().length > 0 ) {
|
||||
scope.addingUser = true;
|
||||
scope.username = $(newUser).val();
|
||||
if(scope.showPassword === false)
|
||||
scope.showPassword = true;
|
||||
}
|
||||
else {
|
||||
scope.addingUser = false;
|
||||
if(scope.loggedInUser !== undefined)
|
||||
scope.username = scope.loggedInUser;
|
||||
scope.showPassword = scope.isSecure;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
app.directive('pwCheck', [function () {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function (scope, elem, attrs, ctrl) {
|
||||
var firstPassword = '#' + attrs.pwCheck;
|
||||
elem.add(firstPassword).on('keyup', function () {
|
||||
scope.$apply(function () {
|
||||
var isMatched = false;
|
||||
if(elem.val().length > 0 && $(firstPassword).val().length > 0)
|
||||
isMatched = (elem.val() === $(firstPassword).val());
|
||||
ctrl.$setValidity('pwmatch', isMatched);
|
||||
scope.matched = isMatched;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
app.controller('SecurityDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||
$scope.loggedInUser = bridgeService.state.loggedInUser;
|
||||
if(bridgeService.state.loggedInUser !== undefined)
|
||||
$scope.username = bridgeService.state.loggedInUser;
|
||||
else
|
||||
$scope.username = ""
|
||||
$scope.secureHueApi = bridgeService.state.securityInfo.secureHueApi;
|
||||
$scope.useLinkButton = bridgeService.state.securityInfo.useLinkButton;
|
||||
$scope.execGarden = bridgeService.state.securityInfo.execGarden;
|
||||
$scope.isSecure = bridgeService.state.securityInfo.isSecure;
|
||||
$scope.matched = false;
|
||||
$scope.addingUser = false;
|
||||
$scope.showPassword = $scope.isSecure;
|
||||
$scope.firstTime = true;
|
||||
|
||||
$scope.setSecurityInfo = function () {
|
||||
bridgeService.changeSecuritySettings($scope.useLinkButton, $scope.secureHueApi, $scope.execGarden);
|
||||
};
|
||||
|
||||
$scope.changePassword = function (password, password2) {
|
||||
bridgeService.changePassword(password, password2);
|
||||
};
|
||||
|
||||
$scope.addUser = function (newUser, password, password2) {
|
||||
bridgeService.addUser(newUser, password, password2);
|
||||
$scope.addingUser = false;
|
||||
if(bridgeService.staet.loggedInUser !== undefined)
|
||||
$scope.username = bridgeService.state.loggedInUser;
|
||||
else
|
||||
$scope.username = ""
|
||||
$scope.showPassword = $scope.isSecure;
|
||||
};
|
||||
|
||||
$scope.delUser = function (newUser) {
|
||||
bridgeService.delUser(newUser);
|
||||
$scope.addingUser = false;
|
||||
if(bridgeService.state.loggedInUser !== undefined)
|
||||
$scope.username = bridgeService.state.loggedInUser;
|
||||
else
|
||||
$scope.username = ""
|
||||
$scope.showPassword = $scope.isSecure;
|
||||
};
|
||||
|
||||
$scope.dismissDialog = function () {
|
||||
ngDialog.close('ngdialog1');
|
||||
};
|
||||
|
||||
$scope.setBlankPassword = function (theElementName) {
|
||||
if($scope.firstTime) {
|
||||
var theElement = "#" + theElementName;
|
||||
$(theElement).strength();
|
||||
$scope.firstTime = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('LogsController', function ($scope, $location, bridgeService) {
|
||||
bridgeService.viewLogs();
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.levels = ["INFO_INT", "WARN_INT", "DEBUG_INT", "TRACE_INT"];
|
||||
@@ -1186,7 +1467,8 @@ function postrenderAction($timeout) {
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
app.controller('ViewingController', function ($scope, $location, $http, $window, bridgeService, ngDialog) {
|
||||
|
||||
app.controller('ViewingController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
|
||||
bridgeService.viewDevices();
|
||||
bridgeService.viewBackups();
|
||||
@@ -1228,6 +1510,9 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
$scope.renumberDevices = function() {
|
||||
bridgeService.renumberDevices();
|
||||
};
|
||||
$scope.pushLinkButton = function() {
|
||||
bridgeService.pushLinkButton();
|
||||
};
|
||||
$scope.backupDeviceDb = function (optionalbackupname) {
|
||||
bridgeService.backupDeviceDb(optionalbackupname);
|
||||
};
|
||||
@@ -1308,7 +1593,7 @@ app.controller('DeleteDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('VeraController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('VeraController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.device_dim_control = "";
|
||||
@@ -1463,7 +1748,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('HarmonyController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('HarmonyController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
bridgeService.viewHarmonyActivities();
|
||||
@@ -1524,7 +1809,7 @@ app.controller('HarmonyController', function ($scope, $location, $http, bridgeSe
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('NestController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('NestController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
bridgeService.viewNestItems();
|
||||
@@ -1625,7 +1910,7 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('HueController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('HueController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.bulk = { devices: [] };
|
||||
@@ -1746,7 +2031,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('HalController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('HalController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.device_dim_control = "";
|
||||
@@ -2051,7 +2336,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('MQTTController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('MQTTController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
bridgeService.viewMQTTDevices();
|
||||
@@ -2096,7 +2381,7 @@ app.controller('MQTTController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('HassController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('HassController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.device_dim_control = "";
|
||||
@@ -2222,7 +2507,7 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('DomoticzController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('DomoticzController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.device_dim_control = "";
|
||||
@@ -2347,7 +2632,7 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
|
||||
}
|
||||
else {
|
||||
$scope.selectAll = true;
|
||||
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
||||
for(var x = 0; x < bridgeService.state.domoticzdevices.length; x++) {
|
||||
if($scope.bulk.devices.indexOf(bridgeService.state.domoticzdevices[x]) < 0)
|
||||
$scope.bulk.devices.push(bridgeService.state.domoticzdevices[x].devicename);
|
||||
}
|
||||
@@ -2377,7 +2662,7 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('LifxController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('LifxController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.device_dim_control = "";
|
||||
@@ -2469,7 +2754,7 @@ app.controller('LifxController', function ($scope, $location, $http, bridgeServi
|
||||
}
|
||||
else {
|
||||
$scope.selectAll = true;
|
||||
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
|
||||
for(var x = 0; x < bridgeService.state.lifxdevices.length; x++) {
|
||||
if($scope.bulk.devices.indexOf(bridgeService.state.lifxdevices[x]) < 0)
|
||||
$scope.bulk.devices.push(bridgeService.state.lifxdevices[x].devicename);
|
||||
}
|
||||
@@ -2499,7 +2784,7 @@ app.controller('LifxController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('SomfyController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||
app.controller('SomfyController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.device_dim_control = "";
|
||||
@@ -2627,8 +2912,7 @@ app.controller('SomfyController', function ($scope, $location, $http, bridgeServ
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('EditController', function ($scope, $location, $http, bridgeService) {
|
||||
bridgeService.viewMapTypes();
|
||||
app.controller('EditController', function ($scope, $location, bridgeService) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
$scope.onDevices = null;
|
||||
@@ -2934,9 +3218,144 @@ app.filter('configuredSomfyDevices', function (bridgeService) {
|
||||
}
|
||||
});
|
||||
|
||||
app.controller('LoginController', function ($scope, $location, Auth) {
|
||||
$scope.failed = false;
|
||||
$scope.loggedIn = Auth.isLoggedIn();
|
||||
$scope.login = function(username, password) {
|
||||
Auth.login(username, password)
|
||||
.then(function() {
|
||||
$location.path("/");
|
||||
}, function() {
|
||||
$scope.failed = true;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$scope.logout = function() {
|
||||
Auth.logout();
|
||||
$scope.loggedIn = Auth.isLoggedIn();
|
||||
$location.path("/login");
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('VersionController', function ($scope, bridgeService) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
});
|
||||
|
||||
app.directive('permission', ['Auth', function(Auth) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
permission: '='
|
||||
},
|
||||
|
||||
link: function (scope, elem, attrs) {
|
||||
scope.$watch(Auth.isLoggedIn, function() {
|
||||
if (Auth.userHasPermission(scope.permission)) {
|
||||
elem.show();
|
||||
} else {
|
||||
elem.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
app.factory('Auth', function($resource, $rootScope, $sessionStorage, $http, $base64, bridgeService){
|
||||
|
||||
var auth = {};
|
||||
|
||||
/**
|
||||
* Saves the current user in the root scope
|
||||
* Call this in the app run() method
|
||||
*/
|
||||
auth.init = function(){
|
||||
if (auth.isLoggedIn()){
|
||||
$rootScope.user = auth.currentUser();
|
||||
}
|
||||
};
|
||||
|
||||
auth.login = function(username, password){
|
||||
var newUserInfo = {};
|
||||
newUserInfo = {
|
||||
username: username,
|
||||
password: password
|
||||
};
|
||||
var theEncodedPayload = $base64.encode(angular.toJson(newUserInfo));
|
||||
return $http.post(bridgeService.state.systemsbase + "/login", theEncodedPayload ).then(
|
||||
function (response) {
|
||||
var theResult = response.data;
|
||||
$sessionStorage.user = theResult.user;
|
||||
$rootScope.user = $sessionStorage.user;
|
||||
bridgeService.state.loggedInUser = $sessionStorage.user.username;
|
||||
bridgeService.getHABridgeVersion();
|
||||
}, function(error) {
|
||||
bridgeService.displayWarn("Login Error: ", error);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
auth.logout = function() {
|
||||
delete $sessionStorage.user;
|
||||
delete $rootScope.user;
|
||||
delete bridgeService.state.loggedInUser;
|
||||
bridgeService.displaySuccess("User Logged Out");
|
||||
};
|
||||
|
||||
|
||||
auth.checkPermissionForView = function(view) {
|
||||
if (!view.requiresAuthentication) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return userHasPermissionForView(view);
|
||||
};
|
||||
|
||||
|
||||
var userHasPermissionForView = function(view){
|
||||
if(!auth.isLoggedIn()){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!view.permissions || !view.permissions.length){
|
||||
return true;
|
||||
}
|
||||
|
||||
return auth.userHasPermission(view.permissions);
|
||||
};
|
||||
|
||||
|
||||
auth.userHasPermission = function(permissions){
|
||||
if(!bridgeService.isSecure())
|
||||
return true;
|
||||
if(!auth.isLoggedIn()){
|
||||
return false;
|
||||
}
|
||||
|
||||
var found = false;
|
||||
angular.forEach(permissions, function(permission, index){
|
||||
if ($sessionStorage.user.user_permissions.indexOf(permission) >= 0){
|
||||
found = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
};
|
||||
|
||||
|
||||
auth.currentUser = function(){
|
||||
if(!bridgeService.isSecure())
|
||||
return "nouser";
|
||||
return $sessionStorage.user;
|
||||
};
|
||||
|
||||
|
||||
auth.isLoggedIn = function(){
|
||||
if(!bridgeService.isSecure())
|
||||
return true;
|
||||
return $sessionStorage.user != null;
|
||||
};
|
||||
|
||||
|
||||
return auth;
|
||||
});
|
||||
@@ -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">
|
||||
<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" />
|
||||
</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="button" class="btn btn-success" ng-click="login(username, password)">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div ng-if="loggedIn">
|
||||
<button type="button" class="btn btn-danger" ng-click="logout()">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
57
src/main/resources/public/views/securitydialog.html
Normal file
57
src/main/resources/public/views/securitydialog.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<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">
|
||||
<label>Secure Folder for scripts/executables</label>
|
||||
<input id="exec-garden" class="form-control"
|
||||
type="text" ng-model="execGarden"
|
||||
placeholder="/home/pi/protectedscripts">
|
||||
</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 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()">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