From 1e74b2716f80c59b686d009fd45ad7ba2b74f9e7 Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Sat, 3 Mar 2018 22:13:54 +0100 Subject: [PATCH 1/9] U2F manager module - Hide U2F key attributs --- .gitignore | 3 +- .../lib/Lemonldap/NG/Manager/Attributes.pm | 74 +++++++++---------- .../site/coffee/sessions.coffee | 2 + lemonldap-ng-manager/site/coffee/u2f.coffee | 2 + .../site/htdocs/static/js/sessions.js | 2 + .../site/htdocs/static/js/sessions.min.js | 2 +- .../site/htdocs/static/js/u2f.js | 2 + .../site/htdocs/static/js/u2f.min.js | 2 +- 8 files changed, 48 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 8b59be3fb..8dd528420 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules -e2e-tests/conf/ +e2e-tests/ lemonldap-ng-common/MYMETA.json lemonldap-ng-common/MYMETA.yml lemonldap-ng-common/Makefile @@ -22,4 +22,3 @@ lemonldap-ng-portal/blib/ lemonldap-ng-portal/t/ .gitignore lemonldap-ng-portal/pm_to_blib -e2e-tests/lemonldap-ng.ini diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm index 1a93f1e51..a90db612c 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm @@ -8,12 +8,12 @@ sub types { 'authParamsText' => { 'test' => sub { 1; - } + } }, 'blackWhiteList' => { 'test' => sub { 1; - } + } }, 'bool' => { 'msgFail' => '__notABoolean__', @@ -36,17 +36,17 @@ sub types { split( /\n/, $@, 0 ) ) ); return $err ? ( 1, "__badExpression__: $err" ) : 1; - } + } }, 'catAndAppList' => { 'test' => sub { 1; - } + } }, 'file' => { 'test' => sub { 1; - } + } }, 'hostname' => { 'form' => 'text', @@ -80,48 +80,48 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- if $_ =~ /exportedvars$/i and defined $conf->{$_}{$val}; } return 1, "__unknownAttrOrMacro__: $val"; - } + } }, 'longtext' => { 'test' => sub { 1; - } + } }, 'menuApp' => { 'test' => sub { 1; - } + } }, 'menuCat' => { 'test' => sub { 1; - } + } }, 'oidcmetadatajson' => { 'test' => sub { 1; - } + } }, 'oidcmetadatajwks' => { 'test' => sub { 1; - } + } }, 'oidcOPMetaDataNode' => { 'test' => sub { 1; - } + } }, 'oidcRPMetaDataNode' => { 'test' => sub { 1; - } + } }, 'password' => { 'msgFail' => '__malformedValue__', 'test' => sub { 1; - } + } }, 'pcre' => { 'form' => 'text', @@ -132,7 +132,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- } }; return $@ ? ( 0, "__badRegexp__: $@" ) : 1; - } + } }, 'PerlModule' => { 'form' => 'text', @@ -142,17 +142,17 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- 'portalskin' => { 'test' => sub { 1; - } + } }, 'portalskinbackground' => { 'test' => sub { 1; - } + } }, 'post' => { 'test' => sub { 1; - } + } }, 'RSAPrivateKey' => { 'test' => sub { @@ -160,7 +160,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:RSA\s+)PRIVATE\s+KEY\s*\-+)?[\r\n]*)?$]s ? 1 : ( 1, '__badPemEncoding__' ); - } + } }, 'RSAPublicKey' => { 'test' => sub { @@ -168,7 +168,7 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+= m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+PUBLIC\s+KEY\s*\-+)?[\r\n]*)?$]s ? 1 : ( 1, '__badPemEncoding__' ); - } + } }, 'RSAPublicKeyOrCertificate' => { 'test' => sub { @@ -176,37 +176,37 @@ m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\ m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+)?[\r\n]*)?$]s ? 1 : ( 1, '__badPemEncoding__' ); - } + } }, 'rule' => { 'test' => sub { 1; - } + } }, 'samlAssertion' => { 'test' => sub { 1; - } + } }, 'samlAttribute' => { 'test' => sub { 1; - } + } }, 'samlIDPMetaDataNode' => { 'test' => sub { 1; - } + } }, 'samlService' => { 'test' => sub { 1; - } + } }, 'samlSPMetaDataNode' => { 'test' => sub { 1; - } + } }, 'select' => { 'test' => sub { @@ -216,19 +216,19 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\ return $test ? 1 : ( 1, "Invalid value '$_[0]' for this select" ); - } + } }, 'subContainer' => { 'keyTest' => qr/\w/, 'test' => sub { 1; - } + } }, 'text' => { 'msgFail' => '__malformedValue__', 'test' => sub { 1; - } + } }, 'trool' => { 'msgFail' => '__authorizedValues__: -1, 0, 1', @@ -1036,7 +1036,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][ split( /\n/, $@, 0 ) ) ); return $err ? ( 1, "__badExpression__: $err" ) : 1; - } + } }, 'type' => 'keyTextContainer' }, @@ -1208,7 +1208,7 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0- and defined $conf->{$_}{$val}; } return 1, "__unknownAttrOrMacro__: $val"; - } + } }, 'type' => 'doubleHash' }, @@ -1490,7 +1490,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][ split( /\n/, $@, 0 ) ) ); return $err ? ( 1, "__badExpression__: $err" ) : 1; - } + } }, 'type' => 'ruleContainer' }, @@ -2986,19 +2986,19 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.] 'default' => 0, 'select' => [ { - 'k' => '0', + 'k' => 0, 'v' => 'unsecuredCookie' }, { - 'k' => '1', + 'k' => 1, 'v' => 'securedCookie' }, { - 'k' => '2', + 'k' => 2, 'v' => 'doubleCookie' }, { - 'k' => '3', + 'k' => 3, 'v' => 'doubleCookieForSingleSession' } ], diff --git a/lemonldap-ng-manager/site/coffee/sessions.coffee b/lemonldap-ng-manager/site/coffee/sessions.coffee index 428b4a133..e2e7646e5 100644 --- a/lemonldap-ng-manager/site/coffee/sessions.coffee +++ b/lemonldap-ng-manager/site/coffee/sessions.coffee @@ -196,6 +196,8 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', session[key] = $scope.localeDate value else if key.match /^(_startTime|_updateTime)$/ session[key] = _stToStr value + else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/ + session[key] = '########' res = [] # 2. Push session keys in reuslt, grouped by categories diff --git a/lemonldap-ng-manager/site/coffee/u2f.coffee b/lemonldap-ng-manager/site/coffee/u2f.coffee index e19d9fa60..c32be1488 100644 --- a/lemonldap-ng-manager/site/coffee/u2f.coffee +++ b/lemonldap-ng-manager/site/coffee/u2f.coffee @@ -197,6 +197,8 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', session[key] = $scope.localeDate value else if key.match /^(_startTime|_updateTime)$/ session[key] = _stToStr value + else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/ + session[key] = '########' res = [] # 2. Push session keys in result, grouped by categories diff --git a/lemonldap-ng-manager/site/htdocs/static/js/sessions.js b/lemonldap-ng-manager/site/htdocs/static/js/sessions.js index ccc91c467..59878cbcc 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/sessions.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/sessions.js @@ -227,6 +227,8 @@ session[key] = $scope.localeDate(value); } else if (key.match(/^(_startTime|_updateTime)$/)) { session[key] = _stToStr(value); + } else if (key.match(/^(_u2fKeyHandle|_u2fUserKey)$/)) { + session[key] = '########'; } } } diff --git a/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js b/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js index 2d199aba4..9a3cbbe27 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js @@ -1 +1 @@ -(function(){var c,e,d,b,g,f,a;b=25;a={_whatToTrace:[function(i,h){return"groupBy=substr("+i+",1)"},function(i,h){return i+"="+h+"*&groupBy="+i},function(i,h){return i+"="+h}],ipAddr:[function(i,h){return"groupBy=net("+i+",16,1)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",32,2)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",48,3)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",128,4)"},function(i,h){return i+"="+h+"&groupBy=_whatToTrace"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],_startTime:[function(i,h){return"groupBy=substr("+i+",8)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",10)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",11)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",12)"},function(i,h){return i+"="+h+"*&groupBy=_whatToTrace"},function(i,h,j){console.log(i);console.log(h);console.log(j);return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],doubleIp:[function(i,h){return i},function(i,h){return"_whatToTrace="+h+"&groupBy=ipAddr"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&ipAddr="+h)}]};f={_whatToTrace:function(i,h,k,j){if(k===1){return i+"="+h+"*&groupBy=substr("+i+","+(k+j+1)+")"}else{return null}},ipAddr:function(i,h,k,j){if(k>0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={session:[{title:"deleteSession",icon:"trash"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteSession=function(){p.waiting=true;return m["delete"](scriptname+"sessions/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false},function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false})};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;IP.title){return 1}else{if(Q.titleb&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"sessions/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={session:[{title:"deleteSession",icon:"trash"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteSession=function(){p.waiting=true;return m["delete"](scriptname+"sessions/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false},function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false})};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}else{if(O.match(/^(_u2fKeyHandle|_u2fUserKey)$/)){t[O]="########"}}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;IP.title){return 1}else{if(Q.titleb&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"sessions/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={session:[{title:"deleteU2FKey",icon:"trash"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteU2FKey=function(){p.waiting=true;m["delete"](scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;IP.title){return 1}else{if(Q.titleb&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"sessions/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={session:[{title:"deleteU2FKey",icon:"trash"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteU2FKey=function(){p.waiting=true;m["delete"](scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}else{if(O.match(/^(_u2fKeyHandle|_u2fUserKey)$/)){t[O]="########"}}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;IP.title){return 1}else{if(Q.titleb&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"sessions/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B Date: Sat, 3 Mar 2018 23:19:30 +0100 Subject: [PATCH 2/9] Append add & verify button + update lang --- .../lib/Lemonldap/NG/Common/Session/REST.pm | 52 ++++++++++++++++++- .../lib/Lemonldap/NG/Manager/U2F.pm | 22 +++++--- lemonldap-ng-manager/site/coffee/u2f.coffee | 42 +++++++++++++-- .../site/htdocs/static/js/u2f.js | 38 ++++++++++++-- .../site/htdocs/static/js/u2f.min.js | 2 +- .../site/htdocs/static/languages/ar.json | 2 + .../site/htdocs/static/languages/en.json | 2 + .../site/htdocs/static/languages/fr.json | 2 + .../site/htdocs/static/languages/it.json | 2 + .../site/htdocs/static/languages/vi.json | 2 + lemonldap-ng-manager/site/templates/u2f.tpl | 6 ++- .../site/htdocs/static/languages/en.json | 2 +- .../site/htdocs/static/languages/fr.json | 4 +- 13 files changed, 156 insertions(+), 22 deletions(-) diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm index e156f1398..1d90dac32 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm @@ -52,7 +52,7 @@ sub delSession { return $self->sendJSONresponse( $req, { result => 1 } ); } -sub delU2FKey { +sub deleteU2FKey { my ( $self, $req ) = @_; return $self->sendJSONresponse( $req, { result => 1 } ) if ( $self->{demoMode} ); @@ -77,6 +77,56 @@ sub delU2FKey { return $self->sendJSONresponse( $req, { result => 1 } ); } +sub addU2FKey { + my ( $self, $req ) = @_; + return $self->sendJSONresponse( $req, { result => 1 } ) + if ( $self->{demoMode} ); + my $mod = $self->getMod($req) + or return $self->sendError( $req, undef, 400 ); + my $id = $req->params('sessionId') + or return $self->sendError( $req, 'sessionId is missing', 400 ); + + # Try to read session + my $session = $self->getApacheSession( $mod, $id ) + or return $self->sendError( $req, undef, 400 ); + + # Delete U2F key attributs and update session + $session->data->{_u2fKeyHandle} = 'TOF'; + $session->data->{_u2fUserKey} = 'TOF'; + $session->update( \%{ $session->data } ); + + Lemonldap::NG::Handler::PSGI::Main->localUnlog( $req, $id ); + if ( $session->error ) { + return $self->sendError( $req, $session->error, 200 ); + } + return $self->sendJSONresponse( $req, { result => 1 } ); +} + +sub verifyU2FKey { + my ( $self, $req ) = @_; + return $self->sendJSONresponse( $req, { result => 1 } ) + if ( $self->{demoMode} ); + my $mod = $self->getMod($req) + or return $self->sendError( $req, undef, 400 ); + my $id = $req->params('sessionId') + or return $self->sendError( $req, 'sessionId is missing', 400 ); + + # Try to read session + my $session = $self->getApacheSession( $mod, $id ) + or return $self->sendError( $req, undef, 400 ); + + # Delete U2F key attributs and update session + $session->data->{_u2fKeyHandle} = 'OK'; + $session->data->{_u2fUserKey} = 'OK'; + $session->update( \%{ $session->data } ); + + Lemonldap::NG::Handler::PSGI::Main->localUnlog( $req, $id ); + if ( $session->error ) { + return $self->sendError( $req, $session->error, 200 ); + } + return $self->sendJSONresponse( $req, { result => 1 } ); +} + sub session { my ( $self, $req, $id, $skey ) = @_; my ( %h, $res ); diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/U2F.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/U2F.pm index 73cb736c5..ffae7971e 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/U2F.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/U2F.pm @@ -37,17 +37,23 @@ sub addRoutes { ['GET'] ) - # DELETE U2F KEY ATTRIBUTS + # DELETE U2F KEY ->addRoute( - u2f => { ':sessionType' => { ':sessionId' => 'delU2FKey' } }, + u2f => { ':sessionType' => { ':sessionId' => 'deleteU2FKey' } }, ['DELETE'] - ); + ) - # UPDATE U2F KEY ATTRIBUTS - # ->addRoute( - # u2f => { ':sessionType' => { ':sessionId' => { ':updateSession' } }, - # ['PUT'] - #); + # ADD U2F KEY + ->addRoute( + u2f => { ':sessionType' => { ':sessionId' => 'addU2FKey' } }, + ['PUT'] + ) + + # VERIFY U2F KEY + ->addRoute( + u2f => { ':sessionType' => { ':sessionId' => 'verifyU2FKey' } }, + ['POST'] + ); $self->setTypes($conf); diff --git a/lemonldap-ng-manager/site/coffee/u2f.coffee b/lemonldap-ng-manager/site/coffee/u2f.coffee index c32be1488..9336c23a5 100644 --- a/lemonldap-ng-manager/site/coffee/u2f.coffee +++ b/lemonldap-ng-manager/site/coffee/u2f.coffee @@ -87,10 +87,18 @@ categories = # Menu entries menu = - session: [ + delU2FKey: [ title: 'deleteU2FKey' icon: 'trash' ] + addU2FKey: [ + title: 'addU2FKey' + icon: 'plus' + ] + verifyU2FKey: [ + title: 'verifyU2FKey' + icon: 'check' + ] home: [] ### @@ -138,7 +146,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', # SESSION MANAGEMENT - # Delete U2F key attributs + # Delete U2F key $scope.deleteU2FKey = -> $scope.waiting = true $http['delete']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) -> @@ -151,6 +159,32 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', $scope.waiting = false $scope.showT = true + # Add U2F key + $scope.addU2FKey = -> + $scope.waiting = true + $http['put']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) -> + $scope.currentSession = null + #$scope.currentScope.remove() + $scope.waiting = false + , (resp) -> + $scope.currentSession = null + #$scope.currentScope.remove() + $scope.waiting = false + $scope.showT = true + + # Verify U2F key + $scope.verifyU2FKey = -> + $scope.waiting = true + $http['post']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) -> + $scope.currentSession = null + #$scope.currentScope.remove() + $scope.waiting = false + , (resp) -> + $scope.currentSession = null + #$scope.currentScope.remove() + $scope.waiting = false + $scope.showT = true + # Open node $scope.stoggle = (scope) -> node = scope.$modelValue @@ -197,8 +231,8 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', session[key] = $scope.localeDate value else if key.match /^(_startTime|_updateTime)$/ session[key] = _stToStr value - else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/ - session[key] = '########' + #else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/ + # session[key] = '########' res = [] # 2. Push session keys in result, grouped by categories diff --git a/lemonldap-ng-manager/site/htdocs/static/js/u2f.js b/lemonldap-ng-manager/site/htdocs/static/js/u2f.js index 5f326c230..afa2e766c 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/u2f.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/u2f.js @@ -104,12 +104,24 @@ }; menu = { - session: [ + delU2FKey: [ { title: 'deleteU2FKey', icon: 'trash' } ], + addU2FKey: [ + { + title: 'addU2FKey', + icon: 'plus' + } + ], + verifyU2FKey: [ + { + title: 'verifyU2FKey', + icon: 'check' + } + ], home: [] }; @@ -173,6 +185,28 @@ }); return $scope.showT = true; }; + $scope.addU2FKey = function() { + $scope.waiting = true; + $http['put'](scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { + $scope.currentSession = null; + return $scope.waiting = false; + }, function(resp) { + $scope.currentSession = null; + return $scope.waiting = false; + }); + return $scope.showT = true; + }; + $scope.verifyU2FKey = function() { + $scope.waiting = true; + $http['post'](scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { + $scope.currentSession = null; + return $scope.waiting = false; + }, function(resp) { + $scope.currentSession = null; + return $scope.waiting = false; + }); + return $scope.showT = true; + }; $scope.stoggle = function(scope) { var node; node = scope.$modelValue; @@ -226,8 +260,6 @@ session[key] = $scope.localeDate(value); } else if (key.match(/^(_startTime|_updateTime)$/)) { session[key] = _stToStr(value); - } else if (key.match(/^(_u2fKeyHandle|_u2fUserKey)$/)) { - session[key] = '########'; } } } diff --git a/lemonldap-ng-manager/site/htdocs/static/js/u2f.min.js b/lemonldap-ng-manager/site/htdocs/static/js/u2f.min.js index 62c83b027..adb80fe3e 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/u2f.min.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/u2f.min.js @@ -1 +1 @@ -(function(){var c,e,d,b,g,f,a;b=25;a={_whatToTrace:[function(i,h){return"groupBy=substr("+i+",1)"},function(i,h){return i+"="+h+"*&groupBy="+i},function(i,h){return i+"="+h}],ipAddr:[function(i,h){return"groupBy=net("+i+",16,1)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",32,2)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",48,3)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",128,4)"},function(i,h){return i+"="+h+"&groupBy=_whatToTrace"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],_startTime:[function(i,h){return"groupBy=substr("+i+",8)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",10)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",11)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",12)"},function(i,h){return i+"="+h+"*&groupBy=_whatToTrace"},function(i,h,j){console.log(i);console.log(h);console.log(j);return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],doubleIp:[function(i,h){return i},function(i,h){return"_whatToTrace="+h+"&groupBy=ipAddr"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&ipAddr="+h)}]};f={_whatToTrace:function(i,h,k,j){if(k===1){return i+"="+h+"*&groupBy=substr("+i+","+(k+j+1)+")"}else{return null}},ipAddr:function(i,h,k,j){if(k>0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={session:[{title:"deleteU2FKey",icon:"trash"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteU2FKey=function(){p.waiting=true;m["delete"](scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}else{if(O.match(/^(_u2fKeyHandle|_u2fUserKey)$/)){t[O]="########"}}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;IP.title){return 1}else{if(Q.titleb&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"sessions/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={delU2FKey:[{title:"deleteU2FKey",icon:"trash"}],addU2FKey:[{title:"addU2FKey",icon:"plus"}],verifyU2FKey:[{title:"verifyU2FKey",icon:"check"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteU2FKey=function(){p.waiting=true;m["delete"](scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.addU2FKey=function(){p.waiting=true;m.put(scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.verifyU2FKey=function(){p.waiting=true;m.post(scriptname+"u2f/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;return p.waiting=false},function(q){p.currentSession=null;return p.waiting=false});return p.showT=true};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;IP.title){return 1}else{if(Q.titleb&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"sessions/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B