mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-16 18:24:36 +00:00
Continue with security impl, starting to gell....
This commit is contained in:
@@ -61,10 +61,12 @@ public class SystemControl extends AuthFramework {
|
||||
log.info("System control service started....");
|
||||
before(SYSTEM_CONTEXT + "/*", (request, response) -> {
|
||||
if(bridgeSettings.getBridgeSecurity().isSecure()) {
|
||||
String pathInfo = request.pathInfo();
|
||||
if(pathInfo == null || !pathInfo.equals(SYSTEM_CONTEXT + "/login")) {
|
||||
User authUser = getAuthenticatedUser(request);
|
||||
if(authUser == null) {
|
||||
response.redirect("/login", 301);
|
||||
// halt(401, "You are not logged in....");
|
||||
halt(401, "{\"message\":\"User not authenticated\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<li class="dropdown">
|
||||
<a id="dLabel1" href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Help <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dLabel">
|
||||
<li><a href="#!/login">Login/Logout</a></li>
|
||||
<li><a href="https://github.com/bwssytems/ha-bridge/blob/master/README.md" target="_blank">Readme</a></li>
|
||||
<li><a href="https://github.com/bwssytems/ha-bridge/wiki/HA-Bridge-FAQs" target="_blank">FAQ</a></li>
|
||||
</ul>
|
||||
@@ -84,6 +85,8 @@
|
||||
<script src="js/angular-scrollable-table.min.js"></script>
|
||||
<script src="js/strength-meter.min.js"></script>
|
||||
<script src="js/angular-base64.min.js"></script>
|
||||
<script src="js/angular-resource.min.js"></script>
|
||||
<script src="js/ngStorage.min.js"></script>
|
||||
<script src="scripts/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
15
src/main/resources/public/js/angular-resource.min.js
vendored
Normal file
15
src/main/resources/public/js/angular-resource.min.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
AngularJS v1.6.1
|
||||
(c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
License: MIT
|
||||
*/
|
||||
(function(W,b){'use strict';function K(q,g){g=g||{};b.forEach(g,function(b,h){delete g[h]});for(var h in q)!q.hasOwnProperty(h)||"$"===h.charAt(0)&&"$"===h.charAt(1)||(g[h]=q[h]);return g}var B=b.$$minErr("$resource"),Q=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;b.module("ngResource",["ng"]).provider("$resource",function(){var q=/^https?:\/\/\[[^\]]*][^/]*/,g=this;this.defaults={stripTrailingSlashes:!0,cancellable:!1,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},
|
||||
"delete":{method:"DELETE"}}};this.$get=["$http","$log","$q","$timeout",function(h,P,L,M){function C(b,e){this.template=b;this.defaults=p({},g.defaults,e);this.urlParams={}}function x(D,e,u,m){function c(a,d){var c={};d=p({},e,d);t(d,function(d,l){y(d)&&(d=d(a));var f;if(d&&d.charAt&&"@"===d.charAt(0)){f=a;var k=d.substr(1);if(null==k||""===k||"hasOwnProperty"===k||!Q.test("."+k))throw B("badmember",k);for(var k=k.split("."),e=0,g=k.length;e<g&&b.isDefined(f);e++){var h=k[e];f=null!==f?f[h]:void 0}}else f=
|
||||
d;c[l]=f});return c}function R(a){return a.resource}function l(a){K(a||{},this)}var q=new C(D,m);u=p({},g.defaults.actions,u);l.prototype.toJSON=function(){var a=p({},this);delete a.$promise;delete a.$resolved;return a};t(u,function(a,d){var b=/^(POST|PUT|PATCH)$/i.test(a.method),e=a.timeout,g=N(a.cancellable)?a.cancellable:q.defaults.cancellable;e&&!S(e)&&(P.debug("ngResource:\n Only numeric values are allowed as `timeout`.\n Promises are not supported in $resource, because the same value would be used for multiple requests. If you are looking for a way to cancel requests, you should use the `cancellable` option."),
|
||||
delete a.timeout,e=null);l[d]=function(f,k,m,D){function u(a){r.catch(E);z.resolve(a)}var G={},v,w,A;switch(arguments.length){case 4:A=D,w=m;case 3:case 2:if(y(k)){if(y(f)){w=f;A=k;break}w=k;A=m}else{G=f;v=k;w=m;break}case 1:y(f)?w=f:b?v=f:G=f;break;case 0:break;default:throw B("badargs",arguments.length);}var F=this instanceof l,n=F?v:a.isArray?[]:new l(v),s={},C=a.interceptor&&a.interceptor.response||R,x=a.interceptor&&a.interceptor.responseError||void 0,H=!!A,I=!!x,z,J;t(a,function(a,d){switch(d){default:s[d]=
|
||||
T(a);case "params":case "isArray":case "interceptor":case "cancellable":}});!F&&g&&(z=L.defer(),s.timeout=z.promise,e&&(J=M(z.resolve,e)));b&&(s.data=v);q.setUrlParams(s,p({},c(v,a.params||{}),G),a.url);var r=h(s).then(function(f){var c=f.data;if(c){if(O(c)!==!!a.isArray)throw B("badcfg",d,a.isArray?"array":"object",O(c)?"array":"object",s.method,s.url);if(a.isArray)n.length=0,t(c,function(a){"object"===typeof a?n.push(new l(a)):n.push(a)});else{var b=n.$promise;K(c,n);n.$promise=b}}f.resource=n;
|
||||
return f}),r=r["finally"](function(){n.$resolved=!0;!F&&g&&(n.$cancelRequest=E,M.cancel(J),z=J=s.timeout=null)}),r=r.then(function(a){var d=C(a);(w||E)(d,a.headers,a.status,a.statusText);return d},H||I?function(a){H&&A(a);return I?x(a):L.reject(a)}:void 0);H&&!I&&r.catch(E);return F?r:(n.$promise=r,n.$resolved=!1,g&&(n.$cancelRequest=u),n)};l.prototype["$"+d]=function(a,c,b){y(a)&&(b=c,c=a,a={});a=l[d].call(this,a,this,c,b);return a.$promise||a}});l.bind=function(a){a=p({},e,a);return x(D,a,u,m)};
|
||||
return l}var E=b.noop,t=b.forEach,p=b.extend,T=b.copy,O=b.isArray,N=b.isDefined,y=b.isFunction,S=b.isNumber,U=b.$$encodeUriQuery,V=b.$$encodeUriSegment;C.prototype={setUrlParams:function(b,e,g){var m=this,c=g||m.template,h,l,p="",a=m.urlParams=Object.create(null);t(c.split(/\W/),function(d){if("hasOwnProperty"===d)throw B("badname");!/^\d+$/.test(d)&&d&&(new RegExp("(^|[^\\\\]):"+d+"(\\W|$)")).test(c)&&(a[d]={isQueryParamValue:(new RegExp("\\?.*=:"+d+"(?:\\W|$)")).test(c)})});c=c.replace(/\\:/g,":");
|
||||
c=c.replace(q,function(a){p=a;return""});e=e||{};t(m.urlParams,function(a,b){h=e.hasOwnProperty(b)?e[b]:m.defaults[b];N(h)&&null!==h?(l=a.isQueryParamValue?U(h,!0):V(h),c=c.replace(new RegExp(":"+b+"(\\W|$)","g"),function(a,b){return l+b})):c=c.replace(new RegExp("(/?):"+b+"(\\W|$)","g"),function(a,b,d){return"/"===d.charAt(0)?d:b+d})});m.defaults.stripTrailingSlashes&&(c=c.replace(/\/+$/,"")||"/");c=c.replace(/\/\.(?=\w+($|\?))/,".");b.url=p+c.replace(/\/\\\./,"/.");t(e,function(a,c){m.urlParams[c]||
|
||||
(b.params=b.params||{},b.params[c]=a)})}};return x}]})})(window,window.angular);
|
||||
//# sourceMappingURL=angular-resource.min.js.map
|
||||
8
src/main/resources/public/js/angular-resource.min.js.map
Normal file
8
src/main/resources/public/js/angular-resource.min.js.map
Normal file
File diff suppressed because one or more lines are too long
1
src/main/resources/public/js/ngStorage.min.js
vendored
Normal file
1
src/main/resources/public/js/ngStorage.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/*! ngstorage 0.3.10 | Copyright (c) 2016 Gias Kay Lee | MIT License */!function(a,b){"use strict";"function"==typeof define&&define.amd?define(["angular"],b):a.hasOwnProperty("angular")?b(a.angular):"object"==typeof exports&&(module.exports=b(require("angular")))}(this,function(a){"use strict";function b(a,b){var c;try{c=a[b]}catch(d){c=!1}if(c){var e="__"+Math.round(1e7*Math.random());try{a[b].setItem(e,e),a[b].removeItem(e,e)}catch(d){c=!1}}return c}function c(c){var d=b(window,c);return function(){var e="ngStorage-";this.setKeyPrefix=function(a){if("string"!=typeof a)throw new TypeError("[ngStorage] - "+c+"Provider.setKeyPrefix() expects a String.");e=a};var f=a.toJson,g=a.fromJson;this.setSerializer=function(a){if("function"!=typeof a)throw new TypeError("[ngStorage] - "+c+"Provider.setSerializer expects a function.");f=a},this.setDeserializer=function(a){if("function"!=typeof a)throw new TypeError("[ngStorage] - "+c+"Provider.setDeserializer expects a function.");g=a},this.supported=function(){return!!d},this.get=function(a){return d&&g(d.getItem(e+a))},this.set=function(a,b){return d&&d.setItem(e+a,f(b))},this.remove=function(a){d&&d.removeItem(e+a)},this.$get=["$rootScope","$window","$log","$timeout","$document",function(d,h,i,j,k){var l,m,n=e.length,o=b(h,c),p=o||(i.warn("This browser does not support Web Storage!"),{setItem:a.noop,getItem:a.noop,removeItem:a.noop}),q={$default:function(b){for(var c in b)a.isDefined(q[c])||(q[c]=a.copy(b[c]));return q.$sync(),q},$reset:function(a){for(var b in q)"$"===b[0]||delete q[b]&&p.removeItem(e+b);return q.$default(a)},$sync:function(){for(var a,b=0,c=p.length;c>b;b++)(a=p.key(b))&&e===a.slice(0,n)&&(q[a.slice(n)]=g(p.getItem(a)))},$apply:function(){var b;if(m=null,!a.equals(q,l)){b=a.copy(l),a.forEach(q,function(c,d){a.isDefined(c)&&"$"!==d[0]&&(p.setItem(e+d,f(c)),delete b[d])});for(var c in b)p.removeItem(e+c);l=a.copy(q)}},$supported:function(){return!!o}};return q.$sync(),l=a.copy(q),d.$watch(function(){m||(m=j(q.$apply,100,!1))}),h.addEventListener&&h.addEventListener("storage",function(b){if(b.key){var c=k[0];c.hasFocus&&c.hasFocus()||e!==b.key.slice(0,n)||(b.newValue?q[b.key.slice(n)]=g(b.newValue):delete q[b.key.slice(n)],l=a.copy(q),d.$apply())}}),h.addEventListener&&h.addEventListener("beforeunload",function(){q.$apply()}),q}]}}return a=a&&a.module?a:window.angular,a.module("ngStorage",[]).provider("$localStorage",c("localStorage")).provider("$sessionStorage",c("sessionStorage"))});
|
||||
@@ -1,73 +1,99 @@
|
||||
var app = angular.module ('habridge', ['ngRoute', 'ngToast', 'rzModule', 'ngDialog', 'base64', 'scrollable-table']);
|
||||
var app = angular.module ('habridge', ['ngRoute', 'ngToast', 'rzModule', 'ngDialog', 'base64', 'scrollable-table', 'ngResource', 'ngStorage']);
|
||||
|
||||
app.config (function ($locationProvider, $routeProvider) {
|
||||
$locationProvider.hashPrefix('!');
|
||||
|
||||
$routeProvider.when ('/', {
|
||||
templateUrl: 'views/configuration.html',
|
||||
controller: 'ViewingController'
|
||||
controller: 'ViewingController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/system', {
|
||||
templateUrl: 'views/system.html',
|
||||
controller: 'SystemController'
|
||||
controller: 'SystemController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/logs', {
|
||||
templateUrl: 'views/logs.html',
|
||||
controller: 'LogsController'
|
||||
controller: 'LogsController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/editdevice', {
|
||||
templateUrl: 'views/editdevice.html',
|
||||
controller: 'EditController'
|
||||
controller: 'EditController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/veradevices', {
|
||||
templateUrl: 'views/veradevice.html',
|
||||
controller: 'VeraController'
|
||||
controller: 'VeraController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/verascenes', {
|
||||
templateUrl: 'views/verascene.html',
|
||||
controller: 'VeraController'
|
||||
controller: 'VeraController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/harmonydevices', {
|
||||
templateUrl: 'views/harmonydevice.html',
|
||||
controller: 'HarmonyController'
|
||||
controller: 'HarmonyController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/harmonyactivities', {
|
||||
templateUrl: 'views/harmonyactivity.html',
|
||||
controller: 'HarmonyController'
|
||||
controller: 'HarmonyController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/nest', {
|
||||
templateUrl: 'views/nestactions.html',
|
||||
controller: 'NestController'
|
||||
controller: 'NestController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/huedevices', {
|
||||
templateUrl: 'views/huedevice.html',
|
||||
controller: 'HueController'
|
||||
controller: 'HueController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/haldevices', {
|
||||
templateUrl: 'views/haldevice.html',
|
||||
controller: 'HalController'
|
||||
controller: 'HalController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/mqttmessages', {
|
||||
templateUrl: 'views/mqttpublish.html',
|
||||
controller: 'MQTTController'
|
||||
controller: 'MQTTController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/hassdevices', {
|
||||
templateUrl: 'views/hassdevice.html',
|
||||
controller: 'HassController'
|
||||
controller: 'HassController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/domoticzdevices', {
|
||||
templateUrl: 'views/domoticzdevice.html',
|
||||
controller: 'DomoticzController'
|
||||
controller: 'DomoticzController',
|
||||
requiresAuthentication: true
|
||||
}).when('/somfydevices', {
|
||||
templateUrl: 'views/somfydevice.html',
|
||||
controller: 'SomfyController'
|
||||
}).otherwise ({
|
||||
controller: 'DomoticzController'
|
||||
templateUrl: 'views/somfydevice.html',
|
||||
controller: 'SomfyController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/lifxdevices', {
|
||||
templateUrl: 'views/lifxdevice.html',
|
||||
controller: 'LifxController'
|
||||
controller: 'LifxController',
|
||||
requiresAuthentication: true
|
||||
}).when ('/login', {
|
||||
templateUrl: 'views/login.html',
|
||||
controller: 'LoginController'
|
||||
}).otherwise ({
|
||||
templateUrl: 'views/configuration.html',
|
||||
controller: 'ViewingController'
|
||||
controller: 'ViewingController',
|
||||
requiresAuthentication: true
|
||||
})
|
||||
});
|
||||
|
||||
app.run( function (bridgeService) {
|
||||
bridgeService.loadBridgeSettings();
|
||||
bridgeService.getHABridgeVersion();
|
||||
bridgeService.getTestUser();
|
||||
bridgeService.getSecurityInfo();
|
||||
bridgeService.viewMapTypes();
|
||||
app.run( function ($rootScope, $location, Auth, bridgeService) {
|
||||
Auth.init();
|
||||
|
||||
$rootScope.$on('$routeChangeStart', function (event, next) {
|
||||
if (!Auth.checkPermissionForView(next)){
|
||||
event.preventDefault();
|
||||
$location.path("/login");
|
||||
}
|
||||
});
|
||||
|
||||
if(Auth.isLoggedIn()) {
|
||||
bridgeService.loadBridgeSettings();
|
||||
bridgeService.getHABridgeVersion();
|
||||
bridgeService.getTestUser();
|
||||
bridgeService.getSecurityInfo();
|
||||
bridgeService.viewMapTypes();
|
||||
}
|
||||
});
|
||||
|
||||
String.prototype.replaceAll = function (search, replace)
|
||||
@@ -3137,14 +3163,132 @@ app.filter('configuredSomfyDevices', function (bridgeService) {
|
||||
}
|
||||
});
|
||||
|
||||
app.controller('LoginController', function ($scope, bridgeService) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
|
||||
app.controller('LoginController', function ($scope, $location, Auth) {
|
||||
$scope.failed = false;
|
||||
$scope.login = function(username, password) {
|
||||
bridgeService.validateUser(username,password);
|
||||
Auth.login(username, password)
|
||||
.then(function() {
|
||||
$location.path("/");
|
||||
}, function() {
|
||||
$scope.failed = true;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('VersionController', function ($scope, bridgeService) {
|
||||
$scope.bridge = bridgeService.state;
|
||||
});
|
||||
|
||||
app.directive('permission', ['Auth', function(Auth) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
permission: '='
|
||||
},
|
||||
|
||||
link: function (scope, elem, attrs) {
|
||||
scope.$watch(Auth.isLoggedIn, function() {
|
||||
if (Auth.userHasPermission(scope.permission)) {
|
||||
elem.show();
|
||||
} else {
|
||||
elem.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
app.factory('Auth', function($resource, $rootScope, $sessionStorage, $http, $base64, bridgeService){
|
||||
|
||||
var auth = {};
|
||||
|
||||
/**
|
||||
* Saves the current user in the root scope
|
||||
* Call this in the app run() method
|
||||
*/
|
||||
auth.init = function(){
|
||||
if (auth.isLoggedIn()){
|
||||
$rootScope.user = currentUser();
|
||||
}
|
||||
};
|
||||
|
||||
auth.login = function(username, password){
|
||||
var newUserInfo = {};
|
||||
newUserInfo = {
|
||||
username: username,
|
||||
password: password
|
||||
};
|
||||
var theEncodedPayload = $base64.encode(angular.toJson(newUserInfo));
|
||||
return $http.post(bridgeService.state.systemsbase + "/login", theEncodedPayload ).then(
|
||||
function (response) {
|
||||
var theResult = response.data;
|
||||
$sessionStorage.user = theResult.user;
|
||||
$rootScope.user = $sessionStorage.user;
|
||||
bridgeService.loadBridgeSettings();
|
||||
bridgeService.getHABridgeVersion();
|
||||
bridgeService.getTestUser();
|
||||
bridgeService.getSecurityInfo();
|
||||
bridgeService.viewMapTypes();
|
||||
}, function(error) {
|
||||
bridgeService.displayWarn("Login Error: ", error);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
auth.logout = function() {
|
||||
delete $sessionStorage.user;
|
||||
delete $rootScope.user;
|
||||
};
|
||||
|
||||
|
||||
auth.checkPermissionForView = function(view) {
|
||||
if (!view.requiresAuthentication) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return userHasPermissionForView(view);
|
||||
};
|
||||
|
||||
|
||||
var userHasPermissionForView = function(view){
|
||||
if(!auth.isLoggedIn()){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!view.permissions || !view.permissions.length){
|
||||
return true;
|
||||
}
|
||||
|
||||
return auth.userHasPermission(view.permissions);
|
||||
};
|
||||
|
||||
|
||||
auth.userHasPermission = function(permissions){
|
||||
if(!auth.isLoggedIn()){
|
||||
return false;
|
||||
}
|
||||
|
||||
var found = false;
|
||||
angular.forEach(permissions, function(permission, index){
|
||||
if ($sessionStorage.user.user_permissions.indexOf(permission) >= 0){
|
||||
found = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
};
|
||||
|
||||
|
||||
auth.currentUser = function(){
|
||||
return $sessionStorage.user;
|
||||
};
|
||||
|
||||
|
||||
auth.isLoggedIn = function(){
|
||||
return $sessionStorage.user != null;
|
||||
};
|
||||
|
||||
|
||||
return auth;
|
||||
});
|
||||
Reference in New Issue
Block a user