mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 00:10:20 +00:00
Continue security implementation
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>com.bwssystems.HABridge</groupId>
|
<groupId>com.bwssystems.HABridge</groupId>
|
||||||
<artifactId>ha-bridge</artifactId>
|
<artifactId>ha-bridge</artifactId>
|
||||||
<version>4.3.1Secure-a</version>
|
<version>4.3.1Secure-b</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>HA Bridge</name>
|
<name>HA Bridge</name>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.bwssystems.HABridge;
|
|||||||
public class BridgeControlDescriptor {
|
public class BridgeControlDescriptor {
|
||||||
private boolean reinit;
|
private boolean reinit;
|
||||||
private boolean stop;
|
private boolean stop;
|
||||||
|
private boolean linkButton;
|
||||||
|
|
||||||
public BridgeControlDescriptor() {
|
public BridgeControlDescriptor() {
|
||||||
super();
|
super();
|
||||||
@@ -22,4 +23,12 @@ public class BridgeControlDescriptor {
|
|||||||
public void setStop(boolean stop) {
|
public void setStop(boolean stop) {
|
||||||
this.stop = stop;
|
this.stop = stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLinkButton() {
|
||||||
|
return linkButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinkButton(boolean linkButton) {
|
||||||
|
this.linkButton = linkButton;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
121
src/main/java/com/bwssystems/HABridge/BridgeSecurity.java
Normal file
121
src/main/java/com/bwssystems/HABridge/BridgeSecurity.java
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class BridgeSecurity {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BridgeSecurity.class);
|
||||||
|
private char[] habridgeKey;
|
||||||
|
private static final byte[] SALT = {
|
||||||
|
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||||
|
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
|
||||||
|
};
|
||||||
|
private BridgeSecurityDescriptor securityDescriptor;
|
||||||
|
|
||||||
|
public BridgeSecurity(char[] theKey, String theData) {
|
||||||
|
habridgeKey = theKey;
|
||||||
|
securityDescriptor = null;
|
||||||
|
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 void setPassword(String aPassword) throws IOException {
|
||||||
|
if(aPassword != null) {
|
||||||
|
securityDescriptor.setUiPassword(String.valueOf(base64Decode(aPassword)));
|
||||||
|
securityDescriptor.setPasswordSet(true);
|
||||||
|
} else {
|
||||||
|
securityDescriptor.setUiPassword(null);
|
||||||
|
securityDescriptor.setPasswordSet(false);
|
||||||
|
}
|
||||||
|
securityDescriptor.setSettingsChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExecGarden(String theGarden) {
|
||||||
|
securityDescriptor.setExecGarden(theGarden);
|
||||||
|
securityDescriptor.setSettingsChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExecGarden() {
|
||||||
|
return securityDescriptor.getExecGarden();
|
||||||
|
}
|
||||||
|
public void setUseLinkButton(boolean useThis) {
|
||||||
|
securityDescriptor.setUseLinkButton(useThis);
|
||||||
|
securityDescriptor.setSettingsChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validatePassword(String targetPassword) throws IOException {
|
||||||
|
if(securityDescriptor.isPasswordSet()) {
|
||||||
|
if(securityDescriptor.getUiPassword().equals(String.valueOf(base64Decode(targetPassword))))
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.warn("validating password when password is not set....");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecure() {
|
||||||
|
return securityDescriptor.isPasswordSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,17 @@
|
|||||||
package com.bwssystems.HABridge;
|
package com.bwssystems.HABridge;
|
||||||
|
|
||||||
public class BridgeSecurityDescriptor {
|
public class BridgeSecurityDescriptor {
|
||||||
private boolean linkButton;
|
|
||||||
private String uiPassword;
|
private String uiPassword;
|
||||||
|
private boolean passwordSet;
|
||||||
|
private boolean useLinkButton;
|
||||||
|
private String execGarden;
|
||||||
|
private boolean settingsChanged;
|
||||||
|
|
||||||
public BridgeSecurityDescriptor() {
|
public BridgeSecurityDescriptor() {
|
||||||
super();
|
super();
|
||||||
}
|
this.setUiPassword(null);
|
||||||
|
this.setPasswordSet(false);
|
||||||
public boolean isLinkButton() {
|
this.setUseLinkButton(false);
|
||||||
return linkButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLinkButton(boolean linkButton) {
|
|
||||||
this.linkButton = linkButton;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUiPassword() {
|
public String getUiPassword() {
|
||||||
@@ -23,4 +21,36 @@ public class BridgeSecurityDescriptor {
|
|||||||
public void setUiPassword(String uiPassword) {
|
public void setUiPassword(String uiPassword) {
|
||||||
this.uiPassword = uiPassword;
|
this.uiPassword = uiPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPasswordSet() {
|
||||||
|
return passwordSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordSet(boolean passwordSet) {
|
||||||
|
this.passwordSet = passwordSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 isSettingsChanged() {
|
||||||
|
return settingsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSettingsChanged(boolean settingsChanged) {
|
||||||
|
this.settingsChanged = settingsChanged;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
|
||||||
private BridgeSettingsDescriptor theBridgeSettings;
|
private BridgeSettingsDescriptor theBridgeSettings;
|
||||||
private BridgeControlDescriptor bridgeControl;
|
private BridgeControlDescriptor bridgeControl;
|
||||||
private BridgeSecurityDescriptor bridgeSecurity;
|
private BridgeSecurity bridgeSecurity;
|
||||||
|
|
||||||
public BridgeSettings() {
|
public BridgeSettings() {
|
||||||
super();
|
super();
|
||||||
bridgeControl = new BridgeControlDescriptor();
|
bridgeControl = new BridgeControlDescriptor();
|
||||||
theBridgeSettings = new BridgeSettingsDescriptor();
|
theBridgeSettings = new BridgeSettingsDescriptor();
|
||||||
bridgeSecurity = new BridgeSecurityDescriptor();
|
bridgeSecurity = null;
|
||||||
String ipV6Stack = System.getProperty("ipV6Stack");
|
String ipV6Stack = System.getProperty("ipV6Stack");
|
||||||
if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) {
|
if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) {
|
||||||
System.setProperty("java.net.preferIPv4Stack" , "true");
|
System.setProperty("java.net.preferIPv4Stack" , "true");
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
public BridgeSettingsDescriptor getBridgeSettingsDescriptor() {
|
public BridgeSettingsDescriptor getBridgeSettingsDescriptor() {
|
||||||
return theBridgeSettings;
|
return theBridgeSettings;
|
||||||
}
|
}
|
||||||
public BridgeSecurityDescriptor getBridgeSecurity() {
|
public BridgeSecurity getBridgeSecurity() {
|
||||||
return bridgeSecurity;
|
return bridgeSecurity;
|
||||||
}
|
}
|
||||||
public void buildSettings() {
|
public void buildSettings() {
|
||||||
@@ -180,6 +180,11 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||||
|
|
||||||
setupInternalTestUser();
|
setupInternalTestUser();
|
||||||
|
|
||||||
|
String theKey = System.getProperty("security.key");
|
||||||
|
if(theKey == null)
|
||||||
|
theKey = "";
|
||||||
|
bridgeSecurity = new BridgeSecurity(theKey.toCharArray(), theBridgeSettings.getSecurityData());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadConfig() {
|
public void loadConfig() {
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ public class BridgeSettingsDescriptor {
|
|||||||
private boolean domoticzconfigured;
|
private boolean domoticzconfigured;
|
||||||
private IpList somfyaddress;
|
private IpList somfyaddress;
|
||||||
private boolean somfyconfigured;
|
private boolean somfyconfigured;
|
||||||
|
|
||||||
private boolean lifxconfigured;
|
private boolean lifxconfigured;
|
||||||
|
private String securityData;
|
||||||
|
|
||||||
public BridgeSettingsDescriptor() {
|
public BridgeSettingsDescriptor() {
|
||||||
super();
|
super();
|
||||||
@@ -295,6 +295,12 @@ public class BridgeSettingsDescriptor {
|
|||||||
public void setLifxconfigured(boolean lifxconfigured) {
|
public void setLifxconfigured(boolean lifxconfigured) {
|
||||||
this.lifxconfigured = lifxconfigured;
|
this.lifxconfigured = lifxconfigured;
|
||||||
}
|
}
|
||||||
|
public String getSecurityData() {
|
||||||
|
return securityData;
|
||||||
|
}
|
||||||
|
public void setSecurityData(String securityData) {
|
||||||
|
this.securityData = securityData;
|
||||||
|
}
|
||||||
public Boolean isValidVera() {
|
public Boolean isValidVera() {
|
||||||
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.net.MulticastSocket;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Timer;
|
||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -121,6 +122,9 @@ public class SystemControl {
|
|||||||
// http://ip_address:port/system/presslinkbutton which sets the link button for device registration
|
// http://ip_address:port/system/presslinkbutton which sets the link button for device registration
|
||||||
put(SYSTEM_CONTEXT + "/presslinkbutton", "application/json", (request, response) -> {
|
put(SYSTEM_CONTEXT + "/presslinkbutton", "application/json", (request, response) -> {
|
||||||
log.info("Link button pressed....");
|
log.info("Link button pressed....");
|
||||||
|
bridgeSettings.getBridgeControl().setLinkButton(true);
|
||||||
|
Timer theTimer = new Timer();
|
||||||
|
theTimer.schedule(new LinkButtonPressed(bridgeSettings.getBridgeControl(), theTimer), 30000);
|
||||||
return null;
|
return null;
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
|||||||
@@ -576,7 +576,7 @@ public class HueMulator {
|
|||||||
|
|
||||||
private String basicListHandler(String type, String userId, String requestIp) {
|
private String basicListHandler(String type, String userId, String requestIp) {
|
||||||
log.debug("hue " + type + " list requested: " + userId + " from " + 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 (theErrors != null) {
|
||||||
if(bridgeSettings.isSettingsChanged())
|
if(bridgeSettings.isSettingsChanged())
|
||||||
bridgeSettingMaster.updateConfigFile();
|
bridgeSettingMaster.updateConfigFile();
|
||||||
@@ -590,7 +590,7 @@ public class HueMulator {
|
|||||||
log.debug("hue group list requested: " + userId + " from " + requestIp);
|
log.debug("hue group list requested: " + userId + " from " + requestIp);
|
||||||
HueError[] theErrors = null;
|
HueError[] theErrors = null;
|
||||||
Map<String, GroupResponse> groupResponseMap = null;
|
Map<String, GroupResponse> groupResponseMap = null;
|
||||||
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||||
if (theErrors == null) {
|
if (theErrors == null) {
|
||||||
if(bridgeSettings.isSettingsChanged())
|
if(bridgeSettings.isSettingsChanged())
|
||||||
bridgeSettingMaster.updateConfigFile();
|
bridgeSettingMaster.updateConfigFile();
|
||||||
@@ -607,7 +607,7 @@ public class HueMulator {
|
|||||||
private Object groupsIdHandler(String groupId, String userId, String requestIp) {
|
private Object groupsIdHandler(String groupId, String userId, String requestIp) {
|
||||||
log.debug("hue group id: <" + groupId + "> requested: " + userId + " from " + requestIp);
|
log.debug("hue group id: <" + groupId + "> requested: " + userId + " from " + requestIp);
|
||||||
HueError[] theErrors = null;
|
HueError[] theErrors = null;
|
||||||
theErrors = bridgeSettings.validateWhitelistUser(userId, null, false);
|
theErrors = bridgeSettings.validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
|
||||||
if (theErrors == null) {
|
if (theErrors == null) {
|
||||||
if(bridgeSettings.isSettingsChanged())
|
if(bridgeSettings.isSettingsChanged())
|
||||||
bridgeSettingMaster.updateConfigFile();
|
bridgeSettingMaster.updateConfigFile();
|
||||||
@@ -632,7 +632,7 @@ public class HueMulator {
|
|||||||
if (bridgeSettings.isTraceupnp())
|
if (bridgeSettings.isTraceupnp())
|
||||||
log.info("Traceupnp: hue lights list requested: " + userId + " from " + requestIp);
|
log.info("Traceupnp: hue lights list requested: " + userId + " from " + requestIp);
|
||||||
log.debug("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 (theErrors == null) {
|
||||||
if(bridgeSettings.isSettingsChanged())
|
if(bridgeSettings.isSettingsChanged())
|
||||||
bridgeSettingMaster.updateConfigFile();
|
bridgeSettingMaster.updateConfigFile();
|
||||||
@@ -642,28 +642,30 @@ public class HueMulator {
|
|||||||
deviceResponseMap = new HashMap<String, DeviceResponse>();
|
deviceResponseMap = new HashMap<String, DeviceResponse>();
|
||||||
for (DeviceDescriptor device : deviceList) {
|
for (DeviceDescriptor device : deviceList) {
|
||||||
DeviceResponse deviceResponse = null;
|
DeviceResponse deviceResponse = null;
|
||||||
if (device.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
|
if(!device.isInactive()) {
|
||||||
CallItem[] callItems = null;
|
if (device.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
|
||||||
try {
|
CallItem[] callItems = null;
|
||||||
if(device.getOnUrl() != null)
|
try {
|
||||||
callItems = aGsonHandler.fromJson(device.getOnUrl(), CallItem[].class);
|
if(device.getOnUrl() != null)
|
||||||
} catch(JsonSyntaxException e) {
|
callItems = aGsonHandler.fromJson(device.getOnUrl(), CallItem[].class);
|
||||||
log.warn("Could not decode Json for url items to get Hue state for device: " + device.getName());
|
} catch(JsonSyntaxException e) {
|
||||||
callItems = null;
|
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])) ||
|
for (int i = 0; callItems != null && i < callItems.length; i++) {
|
||||||
(callItems[i].getItem().getAsString().contains("hueName"))) {
|
if((callItems[i].getType() != null && callItems[i].getType().equals(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) ||
|
||||||
deviceResponse = myHueHome.getHueDeviceInfo(callItems[i], device);
|
(callItems[i].getItem().getAsString().contains("hueName"))) {
|
||||||
i = callItems.length;
|
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,43 +679,51 @@ public class HueMulator {
|
|||||||
UserCreateRequest aNewUser = null;
|
UserCreateRequest aNewUser = null;
|
||||||
String newUser = null;
|
String newUser = null;
|
||||||
String aDeviceType = null;
|
String aDeviceType = null;
|
||||||
|
boolean toContinue = false;
|
||||||
|
|
||||||
if (bridgeSettings.isTraceupnp())
|
if (bridgeSettings.isTraceupnp())
|
||||||
log.info("Traceupnp: hue api user create requested: " + body + " from " + ipAddress);
|
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) {
|
private Object getConfig(String userId, String ipAddress) {
|
||||||
|
|||||||
@@ -18,16 +18,20 @@ import org.slf4j.LoggerFactory;
|
|||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
import com.bwssystems.HABridge.Home;
|
import com.bwssystems.HABridge.Home;
|
||||||
import com.bwssystems.HABridge.api.CallItem;
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
|
||||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||||
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
import com.bwssystems.HABridge.hue.BrightnessDecode;
|
||||||
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
import com.bwssystems.HABridge.hue.DeviceDataDecode;
|
||||||
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
import com.bwssystems.HABridge.hue.MultiCommandUtil;
|
||||||
import com.bwssystems.HABridge.hue.TimeDecode;
|
import com.bwssystems.HABridge.hue.TimeDecode;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
public class TCPHome implements Home {
|
public class TCPHome implements Home {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TCPHome.class);
|
private static final Logger log = LoggerFactory.getLogger(TCPHome.class);
|
||||||
private byte[] sendData;
|
private byte[] sendData;
|
||||||
private Map<String, Socket> theSockets;
|
private Map<String, Socket> theSockets;
|
||||||
|
private Gson aGsonHandler;
|
||||||
|
|
||||||
|
|
||||||
public TCPHome(BridgeSettingsDescriptor bridgeSettings) {
|
public TCPHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
@@ -41,8 +45,12 @@ public class TCPHome implements Home {
|
|||||||
Socket dataSendSocket = null;
|
Socket dataSendSocket = null;
|
||||||
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
|
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
|
||||||
String theUrl = 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 hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||||
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
|
||||||
String hostAddr = null;
|
String hostAddr = null;
|
||||||
@@ -58,14 +66,15 @@ public class TCPHome implements Home {
|
|||||||
try {
|
try {
|
||||||
IPAddress = InetAddress.getByName(hostAddr);
|
IPAddress = InetAddress.getByName(hostAddr);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
// noop
|
return aGsonHandler.toJson(HueErrorResponse.createResponse("901", null, "Cannot connect, Unknown Host", null, "/lights/" + device.getId(), null).getTheErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
||||||
theSockets.put(hostPortion, dataSendSocket);
|
if(theDevice.isPersistent())
|
||||||
|
theSockets.put(hostPortion, dataSendSocket);
|
||||||
} catch (Exception e) {
|
} 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);
|
theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
|
||||||
sendData = theUrlBody.getBytes();
|
sendData = theUrlBody.getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
||||||
outToClient.write(sendData);
|
outToClient.write(sendData);
|
||||||
outToClient.flush();
|
outToClient.flush();
|
||||||
} catch (Exception e) {
|
} catch (IOException e) {
|
||||||
log.warn("Could not send data to TCP socket <<<" + e.getMessage() + ">>>, closing socket: " + theUrl);
|
log.warn("Could not send data to TCP socket <<<" + e.getMessage() + ">>>, closing socket: " + theUrl);
|
||||||
try {
|
try {
|
||||||
dataSendSocket.close();
|
dataSendSocket.close();
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
// noop
|
// 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
|
} else
|
||||||
log.warn("Tcp Call to be presented as tcp://<ip_address>:<port>/payload, format of request unknown: " + theUrl);
|
log.warn("Tcp Call to be presented as tcp://<ip_address>:<port>/payload, format of request unknown: " + theUrl);
|
||||||
@@ -102,6 +125,7 @@ public class TCPHome implements Home {
|
|||||||
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
log.info("TCP Home created.");
|
log.info("TCP Home created.");
|
||||||
theSockets = new HashMap<String, Socket>();
|
theSockets = new HashMap<String, Socket>();
|
||||||
|
aGsonHandler = new GsonBuilder().create();
|
||||||
return this;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bwssystems.hass.test;
|
package com.bwssystems.domoticz.test;
|
||||||
|
|
||||||
import java.util.Iterator;
|
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.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
Reference in New Issue
Block a user