From d4b8b70a8308dd2722e6ebf5e07a6f1e1de2f216 Mon Sep 17 00:00:00 2001 From: Admin Date: Wed, 8 Jun 2016 16:41:46 -0500 Subject: [PATCH] Added Hue Error Handling objects. Adding whitelsit control. --- pom.xml | 2 +- .../HABridge/BridgeSettingsDescriptor.java | 10 ++ .../HABridge/api/hue/HueApiResponse.java | 4 +- .../HABridge/api/hue/HueConfig.java | 6 +- .../bwssystems/HABridge/api/hue/HueError.java | 19 +++ .../HABridge/api/hue/HueErrorDetails.java | 56 +++++++ .../HABridge/api/hue/HueErrorResponse.java | 27 +++ .../HABridge/api/hue/HuePublicConfig.java | 154 ++++++++++++++++++ .../bwssystems/HABridge/hue/HueMulator.java | 106 +++++++++--- 9 files changed, 350 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/api/hue/HueError.java create mode 100644 src/main/java/com/bwssystems/HABridge/api/hue/HueErrorDetails.java create mode 100644 src/main/java/com/bwssystems/HABridge/api/hue/HueErrorResponse.java create mode 100644 src/main/java/com/bwssystems/HABridge/api/hue/HuePublicConfig.java diff --git a/pom.xml b/pom.xml index fdfdbb2..e8c94e8 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 2.0.7-hal-f + 2.0.7-hal-g jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java index 284b46c..c2c1f2a 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java @@ -1,6 +1,9 @@ package com.bwssystems.HABridge; import java.util.List; +import java.util.Map; + +import com.bwssystems.HABridge.api.hue.WhitelistEntry; public class BridgeSettingsDescriptor { private String upnpconfigaddress; @@ -27,6 +30,7 @@ public class BridgeSettingsDescriptor { private IpList haladdress; private String haltoken; private boolean halconfigured; + private Map whitelist; public BridgeSettingsDescriptor() { super(); @@ -188,6 +192,12 @@ public class BridgeSettingsDescriptor { public void setHalconfigured(boolean halconfigured) { this.halconfigured = halconfigured; } + public Map getWhitelist() { + return whitelist; + } + public void setWhitelist(Map whitelist) { + this.whitelist = whitelist; + } public Boolean isValidVera() { if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0) return false; diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HueApiResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/HueApiResponse.java index f9c9533..dd137a4 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/HueApiResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HueApiResponse.java @@ -18,9 +18,9 @@ public class HueApiResponse { private Map rules; private HueConfig config; - public HueApiResponse(String name, String ipaddress, String devicetype, String userid) { + public HueApiResponse(String name, String ipaddress, Map awhitelist) { super(); - this.setConfig(HueConfig.createConfig(name, ipaddress, devicetype, userid)); + this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist)); this.setRules(new HashMap<>()); this.setSensors(new HashMap<>()); this.setSchedules(new HashMap<>()); diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java b/src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java index fc7fc6b..e0cac47 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java @@ -35,7 +35,7 @@ public class HueConfig private String replacesbridgeid; private Map whitelist; - public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) { + public static HueConfig createConfig(String name, String ipaddress, Map awhitelist) { HueConfig aConfig = new HueConfig(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); @@ -57,12 +57,10 @@ public class HueConfig aConfig.setLocaltime(dateFormat.format(new Date())); aConfig.setTimezone(TimeZone.getDefault().getID()); aConfig.setZigbeechannel("6"); - aConfig.setBridgeid("001788FFFE09A206"); + aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress)); aConfig.setModelid("BSB002"); aConfig.setFactorynew(false); aConfig.setReplacesbridgeid(null); - Map awhitelist = new HashMap<>(); - awhitelist.put(userid, WhitelistEntry.createEntry(devicetype)); aConfig.setWhitelist(awhitelist); return aConfig; diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HueError.java b/src/main/java/com/bwssystems/HABridge/api/hue/HueError.java new file mode 100644 index 0000000..b4169b1 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HueError.java @@ -0,0 +1,19 @@ +package com.bwssystems.HABridge.api.hue; + +public class HueError { + + private HueErrorDetails error; + + public HueError(HueErrorDetails error) { + super(); + this.error = error; + } + + public HueErrorDetails getError() { + return error; + } + + public void setError(HueErrorDetails error) { + this.error = error; + } +} diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HueErrorDetails.java b/src/main/java/com/bwssystems/HABridge/api/hue/HueErrorDetails.java new file mode 100644 index 0000000..5c3869d --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HueErrorDetails.java @@ -0,0 +1,56 @@ +package com.bwssystems.HABridge.api.hue; + +public class HueErrorDetails { + private String type; + private String address; + private String description; + private String method_name; + private String resource_name; + private String value; + public HueErrorDetails(String type, String address, String description, String method_name, String resource_name, + String value) { + super(); + this.type = type; + this.address = address; + this.description = description; + this.method_name = method_name; + this.resource_name = resource_name; + this.value = value; + } + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getAddress() { + return address; + } + public void setAddress(String address) { + this.address = address; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getMethod_name() { + return method_name; + } + public void setMethod_name(String method_name) { + this.method_name = method_name; + } + public String getResource_name() { + return resource_name; + } + public void setResource_name(String resource_name) { + this.resource_name = resource_name; + } + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HueErrorResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/HueErrorResponse.java new file mode 100644 index 0000000..3c2b479 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HueErrorResponse.java @@ -0,0 +1,27 @@ +package com.bwssystems.HABridge.api.hue; + +import java.util.ArrayList; + +public class HueErrorResponse { + private ArrayList theErrors; + + public HueErrorResponse() { + super(); + theErrors = new ArrayList(); + } + + public void addError(HueError anError) { + theErrors.add(anError); + } + + public HueError[] getTheErrors() { + HueError theList[] = new HueError[theErrors.size()]; + theList = theErrors.toArray(theList); + return theList; + } + + public void setTheErrors(ArrayList theErrors) { + this.theErrors = theErrors; + } + +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HuePublicConfig.java b/src/main/java/com/bwssystems/HABridge/api/hue/HuePublicConfig.java new file mode 100644 index 0000000..c927446 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HuePublicConfig.java @@ -0,0 +1,154 @@ +package com.bwssystems.HABridge.api.hue; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.StringTokenizer; + +import javax.xml.bind.DatatypeConverter; + +public class HuePublicConfig +{ + private String name; + private String apiversion; + private String swversion; + private String mac; + private String bridgeid; + private String replacesbridgeid; + private Boolean factorynew; + private String modelid; + + public static HuePublicConfig createConfig(String name, String ipaddress) { + HuePublicConfig aConfig = new HuePublicConfig(); + aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress)); + aConfig.setApiversion("1.10.0"); + aConfig.setSwversion("01028090"); + aConfig.setName(name); + aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress)); + aConfig.setModelid("BSB002"); + aConfig.setFactorynew(false); + aConfig.setReplacesbridgeid(null); + + return aConfig; + } + + private static String getMacAddress(String addr) + { + InetAddress ip; + StringBuilder sb = new StringBuilder(); + try { + + ip = InetAddress.getByName(addr); + + NetworkInterface network = NetworkInterface.getByInetAddress(ip); + + byte[] mac = network.getHardwareAddress(); + + for (int i = 0; i < mac.length; i++) { + sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : "")); + } + + } catch (UnknownHostException e) { + + sb.append("00:00:88:00:bb:ee"); + + } catch (SocketException e){ + + sb.append("00:00:88:00:bb:ee"); + + } catch (Exception e){ + + sb.append("00:00:88:00:bb:ee"); + + } + + return sb.toString(); + } + + protected static String getBridgeIdFromMac(String macAddr, String ipAddr) + { + StringTokenizer st = new StringTokenizer(macAddr, ":"); + String bridgeId = ""; + String port = null; + while(st.hasMoreTokens()) { + bridgeId = bridgeId + st.nextToken(); + } + if(ipAddr.contains(":")) { + port = ipAddr.substring(ipAddr.indexOf(":")); + BigInteger bigInt = BigInteger.valueOf(Integer.getInteger(port).intValue()); + byte[] theBytes = bigInt.toByteArray(); + bridgeId = bridgeId + DatatypeConverter.printHexBinary(theBytes); + } + else + bridgeId = bridgeId + "0800"; + return bridgeId; + } + + public String getMac() { + return mac; + } + + public void setMac(String mac) { + this.mac = mac; + } + + public String getSwversion() { + return swversion; + } + + public void setSwversion(String swversion) { + this.swversion = swversion; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + + public String getApiversion() { + return apiversion; + } + + public void setApiversion(String apiversion) { + this.apiversion = apiversion; + } + + + public String getModelid() { + return modelid; + } + + public void setModelid(String modelid) { + this.modelid = modelid; + } + + public String getBridgeid() { + return bridgeid; + } + + public void setBridgeid(String bridgeid) { + this.bridgeid = bridgeid; + } + + public Boolean getFactorynew() { + return factorynew; + } + + public void setFactorynew(Boolean factorynew) { + this.factorynew = factorynew; + } + + public String getReplacesbridgeid() { + return replacesbridgeid; + } + + public void setReplacesbridgeid(String replacesbridgeid) { + this.replacesbridgeid = replacesbridgeid; + } +} diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index da00d50..3a6d7dd 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -7,7 +7,12 @@ import com.bwssystems.HABridge.api.UserCreateRequest; import com.bwssystems.HABridge.api.hue.DeviceResponse; import com.bwssystems.HABridge.api.hue.DeviceState; import com.bwssystems.HABridge.api.hue.HueApiResponse; +import com.bwssystems.HABridge.api.hue.HueError; +import com.bwssystems.HABridge.api.hue.HueErrorDetails; +import com.bwssystems.HABridge.api.hue.HueErrorResponse; +import com.bwssystems.HABridge.api.hue.HuePublicConfig; import com.bwssystems.HABridge.api.hue.StateChangeBody; +import com.bwssystems.HABridge.api.hue.WhitelistEntry; import com.bwssystems.HABridge.dao.*; import com.bwssystems.NestBridge.NestInstruction; import com.bwssystems.NestBridge.NestHome; @@ -62,6 +67,8 @@ import java.nio.charset.Charset; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.StringTokenizer; +import java.util.UUID; import javax.net.ssl.SSLContext; import javax.xml.bind.DatatypeConverter; @@ -137,30 +144,58 @@ public class HueMulator implements HueErrorStringSet { get(HUE_CONTEXT + "/:userid/groups", "application/json", (request, response) -> { String userId = request.params(":userid"); log.debug("hue groups list requested: " + userId + " from " + request.ip()); + response.status(HttpStatus.SC_OK); response.header("Access-Control-Allow-Origin", request.headers("Origin")); - return ""; - } , new JsonTransformer()); + return "{}"; + }); // http://ip_address:port/api/{userId}/groups/0 returns json objects of all groups configured get(HUE_CONTEXT + "/:userid/groups/0", "application/json", (request, response) -> { String userId = request.params(":userid"); log.debug("hue group 0 list requested: " + userId + " from " + request.ip()); + response.status(HttpStatus.SC_OK); response.header("Access-Control-Allow-Origin", request.headers("Origin")); - return ""; - } , new JsonTransformer()); + return "[{\"error\":{\"type\":\"3\", \"address\": \"/api/" + userId + "/groups/" + "0" + "\",\"description\": \"Object not found\"}}]"; + }); // http://ip_address:port/api/{userId}/scenes returns json objects of all scenes configured get(HUE_CONTEXT + "/:userid/scenes", "application/json", (request, response) -> { String userId = request.params(":userid"); log.debug("hue scenes list requested: " + userId + " from " + request.ip()); + response.status(HttpStatus.SC_OK); response.header("Access-Control-Allow-Origin", request.headers("Origin")); - return ""; - } , new JsonTransformer()); + return "{}"; + }); // http://ip_address:port/api/{userId}/schedules returns json objects of all schedules configured get(HUE_CONTEXT + "/:userid/schedules", "application/json", (request, response) -> { String userId = request.params(":userid"); log.debug("hue schedules list requested: " + userId + " from " + request.ip()); + response.status(HttpStatus.SC_OK); response.header("Access-Control-Allow-Origin", request.headers("Origin")); - return ""; - } , new JsonTransformer()); + return "{}"; + }); + // http://ip_address:port/api/{userId}/sensors returns json objects of all sensors configured + get(HUE_CONTEXT + "/:userid/sensors", "application/json", (request, response) -> { + String userId = request.params(":userid"); + log.debug("hue sensors list requested: " + userId + " from " + request.ip()); + response.status(HttpStatus.SC_OK); + response.header("Access-Control-Allow-Origin", request.headers("Origin")); + return "{}"; + }); + // http://ip_address:port/api/{userId}/rules returns json objects of all rules configured + get(HUE_CONTEXT + "/:userid/rules", "application/json", (request, response) -> { + String userId = request.params(":userid"); + log.debug("hue rules list requested: " + userId + " from " + request.ip()); + response.status(HttpStatus.SC_OK); + response.header("Access-Control-Allow-Origin", request.headers("Origin")); + return "{}"; + }); + // http://ip_address:port/api/{userId}/resourcelinks returns json objects of all resourcelinks configured + get(HUE_CONTEXT + "/:userid/resourcelinks", "application/json", (request, response) -> { + String userId = request.params(":userid"); + log.debug("hue resourcelinks list requested: " + userId + " from " + request.ip()); + response.status(HttpStatus.SC_OK); + response.header("Access-Control-Allow-Origin", request.headers("Origin")); + return "{}"; + }); get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> { String userId = request.params(":userid"); if(bridgeSettings.isTraceupnp()) @@ -203,7 +238,7 @@ public class HueMulator implements HueErrorStringSet { aDeviceType = aNewUser.getDevicetype(); } if(newUser == null) - newUser = "lightssystem"; + newUser = getNewUserID(request.ip()); if(aDeviceType == null) aDeviceType = ""; @@ -241,7 +276,7 @@ public class HueMulator implements HueErrorStringSet { aDeviceType = aNewUser.getDevicetype(); } if(newUser == null) - newUser = "lightssystem"; + newUser = getNewUserID(request.ip()); if(aDeviceType == null) aDeviceType = ""; @@ -252,20 +287,17 @@ public class HueMulator implements HueErrorStringSet { return "[{\"success\":{\"username\":\"" + newUser + "\"}}]"; } ); - // http://ip_address:port/api/config returns json objects for the config when no user is given + // http://ip_address:port/api/config returns json objects for the public config when no user is given get(HUE_CONTEXT + "/config", "application/json", (request, response) -> { if(bridgeSettings.isTraceupnp()) log.info("Traceupnp: hue api/config config requested: from " + request.ip()); - log.debug("hue api config requested: from " + request.ip()); - HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", "none"); + log.debug("hue api public config requested, from " + request.ip()); + HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue", bridgeSettings.getUpnpConfigAddress()); response.type("application/json; charset=utf-8"); response.header("Access-Control-Allow-Origin", request.headers("Origin")); response.status(HttpStatus.SC_OK); -// String responseString = null; -// responseString = "[{\"swversion\":\"" + apiResponse.getConfig().getSwversion() + "\",\"apiversion\":\"" + apiResponse.getConfig().getApiversion() + "\",\"name\":\"" + apiResponse.getConfig().getName() + "\",\"mac\":\"" + apiResponse.getConfig().getMac() + "\"}]"; -// return responseString; - return apiResponse.getConfig(); + return apiResponse; }, new JsonTransformer()); // http://ip_address:port/api/{userId}/config returns json objects for the config @@ -274,7 +306,7 @@ public class HueMulator implements HueErrorStringSet { if(bridgeSettings.isTraceupnp()) log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + request.ip()); log.debug("hue api config requested: " + userId + " from " + request.ip()); - HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", userId); + HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getWhitelist()); response.type("application/json; charset=utf-8"); response.header("Access-Control-Allow-Origin", request.headers("Origin")); @@ -286,10 +318,17 @@ public class HueMulator implements HueErrorStringSet { // http://ip_address:port/api/{userId} returns json objects for the full state get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> { String userId = request.params(":userid"); - log.debug("hue api full state requested: " + userId + " from " + request.ip()); response.header("Access-Control-Allow-Origin", request.headers("Origin")); - if(userId.equalsIgnoreCase("undefined")) - return "[{\"error\":{\"address\":\"/\",\"description\":\"unauthorized user\",\"type\":\"1\"}}]"; + response.type("application/json; charset=utf-8"); + response.status(HttpStatus.SC_OK); + if(userId == null || userId.equalsIgnoreCase("undefined") || userId.equalsIgnoreCase("null") || userId.equalsIgnoreCase("")) { + log.debug("hue api full state requested: " + userId + " from " + request.ip() + ". No User supplied"); + HueErrorResponse theErrorResp = new HueErrorResponse(); + theErrorResp.addError(new HueError(new HueErrorDetails("1", "/api/" + userId, "unauthorized user", null, null, null))); + return theErrorResp.getTheErrors(); + } + else + log.debug("hue api full state requested: " + userId + " from " + request.ip()); List descriptorList = repository.findAll(); if (descriptorList == null) { response.status(HttpStatus.SC_NOT_FOUND); @@ -302,11 +341,9 @@ public class HueMulator implements HueErrorStringSet { deviceList.put(descriptor.getId(), deviceResponse); } ); - HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), "My App", userId); + HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getWhitelist()); apiResponse.setLights(deviceList); - response.type("application/json; charset=utf-8"); - response.status(HttpStatus.SC_OK); return apiResponse; }, new JsonTransformer()); @@ -315,18 +352,20 @@ public class HueMulator implements HueErrorStringSet { String userId = request.params(":userid"); String lightId = request.params(":id"); response.header("Access-Control-Allow-Origin", request.headers("Origin")); + response.type("application/json; charset=utf-8"); + response.status(HttpStatus.SC_OK); log.debug("hue light requested: " + lightId + " for user: " + userId + " from " + request.ip()); DeviceDescriptor device = repository.findOne(lightId); if (device == null) { response.status(HttpStatus.SC_NOT_FOUND); - return "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Object not found\"}}]"; + HueErrorResponse theErrorResp = new HueErrorResponse(); + theErrorResp.addError(new HueError(new HueErrorDetails("3", "/api/" + userId + "/lights/" + lightId, "Object not found", null, null, null))); + return theErrorResp.getTheErrors(); } else { log.debug("found device named: " + device.getName()); } DeviceResponse lightResponse = DeviceResponse.createResponse(device); - response.type("application/json; charset=utf-8"); - response.status(HttpStatus.SC_OK); return lightResponse; }, new JsonTransformer()); @@ -1025,6 +1064,19 @@ public class HueMulator implements HueErrorStringSet { return responseString; } + private String getNewUserID(String seed) { + UUID uid = UUID.fromString(seed); + StringTokenizer st = new StringTokenizer(uid.toString(), "-"); + String newUser = ""; + while(st.hasMoreTokens()) { + newUser = newUser + st.nextToken(); + } + + return newUser; + } + private String lookupWhitelistUser() { + + } @Override public void setErrorString(String anError) { errorString = anError;