mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-16 18:24:36 +00:00
Continue adding security
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>4.3.1Secure-d</version>
|
||||
<version>4.3.1Secure-e</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
|
||||
@@ -4,6 +4,7 @@ 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;
|
||||
@@ -63,12 +64,39 @@ public class BridgeSecurity {
|
||||
if(aUser != null) {
|
||||
error = aUser.validate();
|
||||
if(error == null) {
|
||||
User theUser = securityDescriptor.getUsers().get(aUser.getUsername());
|
||||
if(theUser != null) {
|
||||
theUser.setPassword(aUser.getPassword());
|
||||
theUser.setPassword2(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
|
||||
@@ -101,6 +129,7 @@ public class BridgeSecurity {
|
||||
SecurityInfo theInfo = new SecurityInfo();
|
||||
theInfo.setExecGarden(getExecGarden());
|
||||
theInfo.setUseLinkButton(isUseLinkButton());
|
||||
theInfo.setSecureHueApi(isSecureHueApi());
|
||||
theInfo.setSecure(isSecure());
|
||||
return theInfo;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.bwssystems.HABridge;
|
||||
public class SecurityInfo {
|
||||
private boolean useLinkButton;
|
||||
private String execGarden;
|
||||
private boolean seucreHueApi;
|
||||
private boolean secureHueApi;
|
||||
private boolean isSecure;
|
||||
|
||||
public boolean isUseLinkButton() {
|
||||
@@ -18,11 +18,11 @@ public class SecurityInfo {
|
||||
public void setExecGarden(String execGarden) {
|
||||
this.execGarden = execGarden;
|
||||
}
|
||||
public boolean isSeucreHueApi() {
|
||||
return seucreHueApi;
|
||||
public boolean isSecureHueApi() {
|
||||
return secureHueApi;
|
||||
}
|
||||
public void setSeucreHueApi(boolean seucreHueApi) {
|
||||
this.seucreHueApi = seucreHueApi;
|
||||
public void setSecureHueApi(boolean secureHueApi) {
|
||||
this.secureHueApi = secureHueApi;
|
||||
}
|
||||
public boolean isSecure() {
|
||||
return isSecure;
|
||||
|
||||
@@ -13,6 +13,7 @@ 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;
|
||||
@@ -110,12 +111,70 @@ public class SystemControl extends AuthFramework {
|
||||
return theLogServiceMgr.getConfiguredLoggers();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/securityinfo gets the security info for the bridge
|
||||
get (SYSTEM_CONTEXT + "/securityinfo", "application/json", (request, response) -> {
|
||||
log.debug("Get security info");
|
||||
response.status(200);
|
||||
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
|
||||
}, new JsonTransformer());
|
||||
// http://ip_address:port/system/setpassword CORS request
|
||||
options(SYSTEM_CONTEXT + "/setpassword", "application/json", (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", "application/json", (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);
|
||||
|
||||
return errorMessage;
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/adduser CORS request
|
||||
options(SYSTEM_CONTEXT + "/adduser", "application/json", (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
|
||||
post(SYSTEM_CONTEXT + "/adduser", "application/json", (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 {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
}
|
||||
|
||||
return errorMessage;
|
||||
});
|
||||
|
||||
// http://ip_address:port/system/login CORS request
|
||||
options(SYSTEM_CONTEXT + "/login", "application/json", (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", "application/json", (request, response) -> {
|
||||
log.debug("login....");
|
||||
return null;
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/presslinkbutton CORS request
|
||||
options(SYSTEM_CONTEXT + "/presslinkbutton", "application/json", (request, response) -> {
|
||||
@@ -135,20 +194,12 @@ public class SystemControl extends AuthFramework {
|
||||
return null;
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/setpassword CORS request
|
||||
options(SYSTEM_CONTEXT + "/setpassword", "application/json", (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", "application/json", (request, response) -> {
|
||||
log.debug("setpassword....");
|
||||
return null;
|
||||
}, new JsonTransformer());
|
||||
// http://ip_address:port/system/securityinfo gets the security info for the bridge
|
||||
get (SYSTEM_CONTEXT + "/securityinfo", "application/json", (request, response) -> {
|
||||
log.debug("Get security info");
|
||||
response.status(200);
|
||||
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/changesecurityinfo CORS request
|
||||
options(SYSTEM_CONTEXT + "/changesecurityinfo", "application/json", (request, response) -> {
|
||||
@@ -166,25 +217,10 @@ public class SystemControl extends AuthFramework {
|
||||
if(theInfo.getExecGarden() != null)
|
||||
bridgeSettings.getBridgeSecurity().setExecGarden(theInfo.getExecGarden());
|
||||
bridgeSettings.getBridgeSecurity().setUseLinkButton(theInfo.isUseLinkButton());
|
||||
bridgeSettings.getBridgeSecurity().setSecureHueApi(theInfo.isSeucreHueApi());
|
||||
bridgeSettings.getBridgeSecurity().setSecureHueApi(theInfo.isSecureHueApi());
|
||||
return bridgeSettings.getBridgeSecurity().getSecurityInfo();
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/login CORS request
|
||||
options(SYSTEM_CONTEXT + "/login", "application/json", (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", "application/json", (request, response) -> {
|
||||
log.debug("login....");
|
||||
return null;
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/system/logmgmt/update CORS request
|
||||
options(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
|
||||
@@ -61,69 +61,6 @@ legend.form-label {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.strength-meter {
|
||||
position: relative;
|
||||
height: 3px;
|
||||
background: #DDD;
|
||||
margin: 10px auto 20px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.strength-meter:before,
|
||||
.strength-meter:after {
|
||||
content: '';
|
||||
height: inherit;
|
||||
background: transparent;
|
||||
display: block;
|
||||
border-color: #FFF;
|
||||
border-style: solid;
|
||||
border-width: 0 5px 0 5px;
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.strength-meter:before {
|
||||
left: 70px;
|
||||
}
|
||||
|
||||
.strength-meter:after {
|
||||
right: 70px;
|
||||
}
|
||||
|
||||
.strength-meter-fill {
|
||||
background: transparent;
|
||||
height: inherit;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
border-radius: inherit;
|
||||
transition: width 0.5s ease-in-out, background 0.25s;
|
||||
}
|
||||
|
||||
.strength-meter-fill[data-strength='0'] {
|
||||
background: darkred;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.strength-meter-fill[data-strength='1'] {
|
||||
background: orangered;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.strength-meter-fill[data-strength='2'] {
|
||||
background: orange;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.strength-meter-fill[data-strength='3'] {
|
||||
background: yellowgreen;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.strength-meter-fill[data-strength='4'] {
|
||||
background: green;
|
||||
width: 100%;
|
||||
}
|
||||
.msg-block {
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
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>
|
||||
@@ -81,7 +82,8 @@
|
||||
<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/zxcvbn.js"></script>
|
||||
<script src="js/strength-meter.min.js"></script>
|
||||
<script src="js/angular-base64.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}}())}();
|
||||
@@ -1 +0,0 @@
|
||||
!function(){"use strict";angular.module("zxcvbn",[]).directive("zxcvbn",function(){return{scope:{password:"=",extras:"=?",data:"=?"},restrict:"E",template:"{{ display.crack_times_display }}",link:function(r,a,t){r.$watch("password",function(a){angular.isString(a)&&(r.extras?r.timeToCrack=zxcvbn(a,r.extras):r.timeToCrack=zxcvbn(a),"data"in t&&r.timeToCrack&&(r.data=angular.copy(r.timeToCrack)),r.display=angular.copy(r.timeToCrack))})}}})}(),function(){"use strict";angular.module("zxcvbn").directive("zxcvbn",function(){return{require:"ngModel",restrict:"A",scope:{zxResult:"=?zxcvbn",zxExtras:"=?",zxMinScore:"@?"},link:function(r,a,t,e){r.runZxcvbn=function(){angular.isUndefined(r.zxPassword)&&(r.zxPassword=""),angular.isDefined(r.zxExtrasArray)&&r.zxExtrasArray.length>0?r.zxResult=zxcvbn(r.zxPassword,r.zxExtrasArray):r.zxResult=zxcvbn(r.zxPassword)},r.isForm=function(r){try{return"FormController"===Object.getPrototypeOf(r).constructor.name}catch(a){return!1}},r.setZxExtrasWatcher=function(){var a=r.zxExtras;angular.isFunction(r.zxExtrasWatcher)&&r.zxExtrasWatcher(),r.zxExtrasWatcher=void 0,angular.isDefined(a)&&(angular.isArray(a)?r.zxArrayWatcher():r.isForm(a)&&r.zxFormWatcher())},r.zxFormWatcher=function(){var a=r.zxExtras;console.assert(r.isForm(a),"zx-extras element is some how not a form."),r.zxExtrasWatcher=r.$watch(function(){var r=[],t=new RegExp("^(?!\\$|__)");for(var e in a)t.test(e)&&a[e].hasOwnProperty("$viewValue")&&-1===e.toLowerCase().indexOf("password")&&r.push(a[e].$viewValue);return r},function(a){r.zxExtrasArray=[];for(var t=0;t<a.length;t++)angular.isString(a[t])&&r.zxExtrasArray.push(a[t]);e.$validate()},!0)},r.zxArrayWatcher=function(){r.zxExtrasWatcher=r.$watch("zxExtras",function(a){r.zxExtrasArray=a,e.$validate()},!0)},r.setZxExtrasWatcher(),e.$validators.passwordStrength=function(a){var t=parseInt(r.zxMinScore);return t=isNaN(t)||0>t||t>4?0:t,r.zxPassword=a,r.runZxcvbn(),t<=r.zxResult.score},t.$observe("zxExtras",function(){r.setZxExtrasWatcher(),e.$validate()}),t.$observe("zxMinScore",function(a){r.zxMinScore=a,e.$validate()})}}})}();
|
||||
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,4 +1,4 @@
|
||||
var app = angular.module ('habridge', ['ngRoute', 'ngToast', 'rzModule', 'ngDialog', 'zxcvbn', 'scrollable-table']);
|
||||
var app = angular.module ('habridge', ['ngRoute', 'ngToast', 'rzModule', 'ngDialog', 'base64', 'scrollable-table']);
|
||||
|
||||
app.config (function ($locationProvider, $routeProvider) {
|
||||
$locationProvider.hashPrefix('!');
|
||||
@@ -79,12 +79,12 @@ String.prototype.replaceAll = function (search, replace)
|
||||
};
|
||||
|
||||
|
||||
app.service ('bridgeService', function ($http, $window, ngToast, zxcvbn) {
|
||||
app.service ('bridgeService', function ($http, $base64, 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: "", securityInfo: {}};
|
||||
showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: "", viewDevId: "", queueDevId: "", securityInfo: {}, username: "test"};
|
||||
|
||||
this.displayWarn = function(errorTitle, error) {
|
||||
var toastContent = errorTitle;
|
||||
@@ -198,7 +198,7 @@ app.service ('bridgeService', function ($http, $window, ngToast, zxcvbn) {
|
||||
);
|
||||
};
|
||||
|
||||
this.changeSecuritySettings = function (useLinkButton, secureHueApi, execGarden, aPassword, aPassword2) {
|
||||
this.changeSecuritySettings = function (useLinkButton, secureHueApi, execGarden) {
|
||||
var newSecurityInfo = {};
|
||||
newSecurityInfo = {
|
||||
useLinkButton: useLinkButton,
|
||||
@@ -216,6 +216,42 @@ app.service ('bridgeService', function ($http, $window, ngToast, zxcvbn) {
|
||||
);
|
||||
};
|
||||
|
||||
this.changePassword = function (aPassword, aPassword2) {
|
||||
var newUserInfo = {};
|
||||
newUserInfo = {
|
||||
username: self.state.username,
|
||||
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.post(this.state.systemsbase + "/adduser", theEncodedPayload ).then(
|
||||
function (response) {
|
||||
self.displaySuccess("User added")
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("User add Error: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.pushLinkButton = function () {
|
||||
return $http.put(this.state.systemsbase + "/presslinkbutton").then(
|
||||
function (response) {
|
||||
@@ -227,11 +263,6 @@ app.service ('bridgeService', function ($http, $window, ngToast, zxcvbn) {
|
||||
);
|
||||
};
|
||||
|
||||
this.score = function() {
|
||||
var compute = zxcvbn.apply(null, arguments);
|
||||
return compute && compute.score;
|
||||
}
|
||||
|
||||
this.aContainsB = function (a, b) {
|
||||
return a.indexOf(b) >= 0;
|
||||
}
|
||||
@@ -1004,7 +1035,7 @@ app.service ('bridgeService', function ($http, $window, ngToast, zxcvbn) {
|
||||
};
|
||||
});
|
||||
|
||||
app.controller ('SystemController', function ($scope, $location, $http, $window, bridgeService, ngDialog) {
|
||||
app.controller ('SystemController', function ($scope, $location, bridgeService, ngDialog) {
|
||||
bridgeService.viewConfigs();
|
||||
bridgeService.loadBridgeSettings();
|
||||
$scope.bridge = bridgeService.state;
|
||||
@@ -1179,26 +1210,58 @@ app.controller ('SystemController', function ($scope, $location, $http, $window,
|
||||
};
|
||||
|
||||
$scope.changeSeuritySettings = function () {
|
||||
bridgeService.getSecurityInfo();
|
||||
ngDialog.open({
|
||||
template: 'securityDialog',
|
||||
template: 'views/securityDialog.html',
|
||||
controller: 'SecurityDialogCtrl',
|
||||
className: 'ngdialog-theme-default'
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
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 () {
|
||||
// console.info(elem.val() === $(firstPassword).val());
|
||||
ctrl.$setValidity('pwmatch', elem.val() === $(firstPassword).val());
|
||||
scope.matched = (elem.val() === $(firstPassword).val());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
app.controller('SecurityDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||
$scope.useLinkButton = bridgeService.state.securityInfo.useLinkButton;
|
||||
$scope.username = bridgeService.state.username;
|
||||
$scope.secureHueApi = bridgeService.state.securityInfo.secureHueApi;
|
||||
$scope.useLinkButton = bridgeService.state.securityInfo.useLinkButton;
|
||||
$scope.execGarden = bridgeService.state.securityInfo.execGarden;
|
||||
$scope.matched = false;
|
||||
|
||||
$scope.setSecurityInfo = function () {
|
||||
bridgeService.changeSecuritySettings($scope.useLinkButton, $scope.secureHueApi, $scope.execGarden);
|
||||
};
|
||||
|
||||
$scope.changePassword = function () {
|
||||
bridgeService.changePassword($scope.password, $scope.password2);
|
||||
};
|
||||
|
||||
$scope.dismissDialog = function () {
|
||||
ngDialog.close('ngdialog1');
|
||||
bridgeService.changeSecuritySettings($scope.useLinkButton, $scope.secureHueApi, $scope.execGarden, $scope.password, $scope.password2);
|
||||
};
|
||||
|
||||
$scope.setBlankPassword = function (theElementName) {
|
||||
$scope.password = "";
|
||||
var theElement = "#" + theElementName;
|
||||
$(theElement).strength();
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('LogsController', function ($scope, $location, $http, $window, bridgeService) {
|
||||
app.controller('LogsController', function ($scope, $location, bridgeService) {
|
||||
bridgeService.viewLogs();
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.levels = ["INFO_INT", "WARN_INT", "DEBUG_INT", "TRACE_INT"];
|
||||
@@ -1260,7 +1323,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();
|
||||
@@ -1385,7 +1449,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 = "";
|
||||
@@ -1540,7 +1604,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();
|
||||
@@ -1601,7 +1665,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();
|
||||
@@ -1702,7 +1766,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: [] };
|
||||
@@ -1823,7 +1887,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 = "";
|
||||
@@ -2128,7 +2192,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();
|
||||
@@ -2173,7 +2237,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 = "";
|
||||
@@ -2299,7 +2363,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 = "";
|
||||
@@ -2454,7 +2518,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 = "";
|
||||
@@ -2576,7 +2640,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 = "";
|
||||
@@ -2704,7 +2768,7 @@ app.controller('SomfyController', function ($scope, $location, $http, bridgeServ
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('EditController', function ($scope, $location, $http, bridgeService) {
|
||||
app.controller('EditController', function ($scope, $location, bridgeService) {
|
||||
bridgeService.viewMapTypes();
|
||||
$scope.bridge = bridgeService.state;
|
||||
$scope.device = bridgeService.state.device;
|
||||
@@ -3011,58 +3075,6 @@ app.filter('configuredSomfyDevices', function (bridgeService) {
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('passwordCount', [function() {
|
||||
return function(value, peak) {
|
||||
value = angular.isString(value) ? value : '';
|
||||
peak = isFinite(peak) ? peak : 7;
|
||||
|
||||
return value && (value.length > peak ? peak + '+' : value.length);
|
||||
};
|
||||
}]);
|
||||
|
||||
app.directive('okPassword', ['bridgeService', function(bridgeService) {
|
||||
return {
|
||||
// restrict to only attribute and class
|
||||
restrict: 'AC',
|
||||
|
||||
// use the NgModelController
|
||||
require: 'ngModel',
|
||||
|
||||
// add the NgModelController as a dependency to your link function
|
||||
link: function($scope, $element, $attrs, ngModelCtrl) {
|
||||
$element.on('blur change keydown', function(evt) {
|
||||
$scope.$evalAsync(function($scope) {
|
||||
// update the $scope.password with the element's value
|
||||
var pwd = $scope.password = $element.val();
|
||||
|
||||
// resolve password strength score using zxcvbn service
|
||||
$scope.passwordStrength = pwd ? (pwd.length > 7 && bridgeService.score(pwd) || 0) : null;
|
||||
|
||||
// define the validity criterion for okPassword constraint
|
||||
ngModelCtrl.$setValidity('okPassword', $scope.passwordStrength >= 2);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
app.controller('FormController', function($scope) {});
|
||||
|
||||
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 () {
|
||||
// console.info(elem.val() === $(firstPassword).val());
|
||||
ctrl.$setValidity('pwmatch', elem.val() === $(firstPassword).val());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
app.controller('VersionController', function ($scope, bridgeService) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
});
|
||||
|
||||
45
src/main/resources/public/views/securitydialog.html
Normal file
45
src/main/resources/public/views/securitydialog.html
Normal file
@@ -0,0 +1,45 @@
|
||||
<div class="form-container ngdialog-message" ng-controller="SecurityDialogCtrl" postrender-action="setBlankPassword('password-1')">
|
||||
|
||||
<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>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 class="btn btn-warning" ng-click="changePassword()">Change Password</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-success" ng-click="dismissDialog()">Dismiss</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -512,52 +512,4 @@
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="securityDialog">
|
||||
<div class="form-container">
|
||||
|
||||
<form name="securityForm" role="form" ng-controller="FormController">
|
||||
<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">
|
||||
<label>Change Password</label>
|
||||
<div class="form-hint">If you are exposing this to the internet, you use a sufficiently strong password. Password must be more than 7 characters.</div>
|
||||
|
||||
<input type="password" class="form-control ok-password" ng-class="(securityForm.password.$dirty && securityForm.password.$invalid) ? 'error' : ''" id="password" name="password" placeholder="Enter Password" ng-required="true" ng-model="password">
|
||||
|
||||
<div class="label password-count" ng-class="password.length > 7 ? 'label-success' : 'label-danger'" ng-cloak>{{ password | passwordCount:7 }}</div>
|
||||
|
||||
<div class="strength-meter">
|
||||
<div class="strength-meter-fill" data-strength="{{passwordStrength}}"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Confirm Password</label>
|
||||
<input id="password-2" class="form-control" type="password" ng-model="password2" ng-required="true" pw-check="password" />
|
||||
<div class="msg-block" ng-show="securityForm.$error">
|
||||
<span class="msg-error" ng-show="securityForm.pw2.$error.pwmatch">Passwords don't match.</span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-disabled="securityForm.$invalid" ng-click="setSecurityInfo()">Update</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
Reference in New Issue
Block a user