From b000215b26d4498714538706cbd284ed17b874fe Mon Sep 17 00:00:00 2001 From: Admin Date: Wed, 22 Mar 2017 16:35:19 -0500 Subject: [PATCH] Continue security implementation --- pom.xml | 2 +- .../HABridge/BridgeControlDescriptor.java | 9 ++ .../bwssystems/HABridge/BridgeSecurity.java | 121 +++++++++++++++++ .../HABridge/BridgeSecurityDescriptor.java | 48 +++++-- .../bwssystems/HABridge/BridgeSettings.java | 13 +- .../HABridge/BridgeSettingsDescriptor.java | 8 +- .../bwssystems/HABridge/SystemControl.java | 4 + .../bwssystems/HABridge/hue/HueMulator.java | 122 ++++++++++-------- .../HABridge/plugins/tcp/TCPHome.java | 44 +++++-- .../HABridge/plugins/tcp/TcpDevice.java | 18 +++ .../test/DomoticzDeviceConstructor.java | 2 +- .../test/DomoticzStructureTestCase.java | 2 +- 12 files changed, 310 insertions(+), 83 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/BridgeSecurity.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/tcp/TcpDevice.java rename src/test/java/com/bwssystems/{hass => domoticz}/test/DomoticzDeviceConstructor.java (98%) rename src/test/java/com/bwssystems/{hass => domoticz}/test/DomoticzStructureTestCase.java (84%) diff --git a/pom.xml b/pom.xml index f133451..68830f0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 4.3.1Secure-a + 4.3.1Secure-b jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/BridgeControlDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeControlDescriptor.java index 7fa4afd..1e90423 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeControlDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeControlDescriptor.java @@ -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; + } } diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSecurity.java b/src/main/java/com/bwssystems/HABridge/BridgeSecurity.java new file mode 100644 index 0000000..fca261c --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/BridgeSecurity.java @@ -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); + } +} diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSecurityDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSecurityDescriptor.java index 857a9b8..0288d3a 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSecurityDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSecurityDescriptor.java @@ -1,19 +1,17 @@ package com.bwssystems.HABridge; public class BridgeSecurityDescriptor { - private boolean linkButton; private String uiPassword; + private boolean passwordSet; + private boolean useLinkButton; + private String execGarden; + private boolean settingsChanged; public BridgeSecurityDescriptor() { super(); - } - - public boolean isLinkButton() { - return linkButton; - } - - public void setLinkButton(boolean linkButton) { - this.linkButton = linkButton; + this.setUiPassword(null); + this.setPasswordSet(false); + this.setUseLinkButton(false); } public String getUiPassword() { @@ -23,4 +21,36 @@ public class BridgeSecurityDescriptor { public void setUiPassword(String 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; + } } diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java index b80f42f..1028712 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java @@ -26,14 +26,14 @@ public class BridgeSettings extends BackupHandler { private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class); private BridgeSettingsDescriptor theBridgeSettings; private BridgeControlDescriptor bridgeControl; - private BridgeSecurityDescriptor bridgeSecurity; + private BridgeSecurity bridgeSecurity; public BridgeSettings() { super(); bridgeControl = new BridgeControlDescriptor(); theBridgeSettings = new BridgeSettingsDescriptor(); - bridgeSecurity = new BridgeSecurityDescriptor(); - String ipV6Stack = System.getProperty("ipV6Stack"); + bridgeSecurity = null; + String ipV6Stack = System.getProperty("ipV6Stack"); if(ipV6Stack == null || !ipV6Stack.equalsIgnoreCase("true")) { System.setProperty("java.net.preferIPv4Stack" , "true"); } @@ -45,7 +45,7 @@ public class BridgeSettings extends BackupHandler { public BridgeSettingsDescriptor getBridgeSettingsDescriptor() { return theBridgeSettings; } - public BridgeSecurityDescriptor getBridgeSecurity() { + public BridgeSecurity getBridgeSecurity() { return bridgeSecurity; } public void buildSettings() { @@ -180,6 +180,11 @@ public class BridgeSettings extends BackupHandler { setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-"); setupInternalTestUser(); + + String theKey = System.getProperty("security.key"); + if(theKey == null) + theKey = ""; + bridgeSecurity = new BridgeSecurity(theKey.toCharArray(), theBridgeSettings.getSecurityData()); } public void loadConfig() { diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java index 103b661..019d7a3 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java @@ -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; diff --git a/src/main/java/com/bwssystems/HABridge/SystemControl.java b/src/main/java/com/bwssystems/HABridge/SystemControl.java index a31c6bc..0cdd456 100644 --- a/src/main/java/com/bwssystems/HABridge/SystemControl.java +++ b/src/main/java/com/bwssystems/HABridge/SystemControl.java @@ -12,6 +12,7 @@ import java.net.MulticastSocket; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Timer; import org.apache.http.HttpStatus; 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 put(SYSTEM_CONTEXT + "/presslinkbutton", "application/json", (request, response) -> { log.info("Link button pressed...."); + bridgeSettings.getBridgeControl().setLinkButton(true); + Timer theTimer = new Timer(); + theTimer.schedule(new LinkButtonPressed(bridgeSettings.getBridgeControl(), theTimer), 30000); return null; }, new JsonTransformer()); diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index bab604f..a1d0296 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -576,7 +576,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 +590,7 @@ public class HueMulator { log.debug("hue group list requested: " + userId + " from " + requestIp); HueError[] theErrors = null; Map 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 +607,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 +632,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 +642,30 @@ public class HueMulator { deviceResponseMap = new HashMap(); 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,43 +679,51 @@ 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 = ""; - - 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 = ""; + + 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) { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java index d359e96..7419dff 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java @@ -18,16 +18,20 @@ import org.slf4j.LoggerFactory; import com.bwssystems.HABridge.BridgeSettingsDescriptor; 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 theSockets; + private Gson aGsonHandler; public TCPHome(BridgeSettingsDescriptor 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://:/payload, format of request unknown: " + theUrl); @@ -102,6 +125,7 @@ public class TCPHome implements Home { public Home createHome(BridgeSettingsDescriptor bridgeSettings) { log.info("TCP Home created."); theSockets = new HashMap(); + aGsonHandler = new GsonBuilder().create(); return this; } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TcpDevice.java b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TcpDevice.java new file mode 100644 index 0000000..3888b4e --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TcpDevice.java @@ -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; + } +} diff --git a/src/test/java/com/bwssystems/hass/test/DomoticzDeviceConstructor.java b/src/test/java/com/bwssystems/domoticz/test/DomoticzDeviceConstructor.java similarity index 98% rename from src/test/java/com/bwssystems/hass/test/DomoticzDeviceConstructor.java rename to src/test/java/com/bwssystems/domoticz/test/DomoticzDeviceConstructor.java index fb08254..9ea5791 100644 --- a/src/test/java/com/bwssystems/hass/test/DomoticzDeviceConstructor.java +++ b/src/test/java/com/bwssystems/domoticz/test/DomoticzDeviceConstructor.java @@ -1,4 +1,4 @@ -package com.bwssystems.hass.test; +package com.bwssystems.domoticz.test; import java.util.Iterator; diff --git a/src/test/java/com/bwssystems/hass/test/DomoticzStructureTestCase.java b/src/test/java/com/bwssystems/domoticz/test/DomoticzStructureTestCase.java similarity index 84% rename from src/test/java/com/bwssystems/hass/test/DomoticzStructureTestCase.java rename to src/test/java/com/bwssystems/domoticz/test/DomoticzStructureTestCase.java index 54d1ecd..a25b702 100644 --- a/src/test/java/com/bwssystems/hass/test/DomoticzStructureTestCase.java +++ b/src/test/java/com/bwssystems/domoticz/test/DomoticzStructureTestCase.java @@ -1,4 +1,4 @@ -package com.bwssystems.hass.test; +package com.bwssystems.domoticz.test; import org.junit.Assert; import org.junit.Test;