...
 
Commits (57)
......@@ -294,6 +294,8 @@ $(SRCPORTALDIR)/site/htdocs/static/common/js/%.js: $(SRCPORTALDIR)/site/coffee/%
@if which coffee >/dev/null; then \
echo "Compiling $(SRCPORTALDIR)/site/coffee/$*.coffee"; \
coffee -c -o $(SRCPORTALDIR)/site/htdocs/static/common/js/ $(SRCPORTALDIR)/site/coffee/$*.coffee; \
else \
echo "Can't find coffee"; \
fi
$(SRCMANAGERDIR)/site/htdocs/static/js/%.js: $(SRCMANAGERDIR)/site/coffee/%.coffee
......
......@@ -86,7 +86,7 @@
"authentication" : "Demo",
"cfgAuthor" : "The LemonLDAP::NG team",
"cfgNum" : 1,
"cfgVersion" : "2.0.2",
"cfgVersion" : "2.0.3",
"cookieName" : "lemonldap",
"demoExportedVars" : {
"cn" : "cn",
......@@ -119,10 +119,10 @@
"namespace" : "lemonldap-ng-sessions"
},
"locationRules" : {
"auth.example.com" : {
"(?#checkUser)^/checkuser": "$uid eq \"dwho\"",
"(?#errors)^/lmerror/": "accept",
"default" : "accept"
"auth.__DNSDOMAIN__" : {
"(?#checkUser)^/checkuser" : "$uid eq \"dwho\"",
"(?#errors)^/lmerror/" : "accept",
"default" : "accept"
},
"manager.__DNSDOMAIN__" : {
"(?#Configuration)^/(manager\\.html|$)" : "$uid eq \"dwho\"",
......
......@@ -39,6 +39,11 @@ useRedirectOnError = 0
enabledModules = conf, sessions, notifications, 2ndFA, viewer
protection = manager
viewerHiddenKeys = samlIDPMetaDataNodes samlSPMetaDataNodes portalDisplayLogout captcha_login_enabled
viewerAllowBrowser = 1
viewerAllowDiff = 1
staticPrefix = /static
languages = fr, en, vi, ar, de, it, zh
templateDir = __pwd__/lemonldap-ng-manager/site/templates
......
......@@ -362,8 +362,9 @@ languages = fr, en, vi, ar
enabledModules = conf, sessions, notifications, 2ndFA, viewer
; Viewer options - Default values
;viewerHiddenPK = samlIDPMetaDataNodes samlSPMetaDataNodes
;viewerHiddenKeys = samlIDPMetaDataNodes samlSPMetaDataNodes
;viewerAllowBrowser = 0
;viewerAllowDiff = 0
;[node-handler]
;
......
......@@ -7,6 +7,7 @@ use Encode;
our $VERSION = '2.0.0';
our $initDone;
$YAML::Numify = 1;
sub Lemonldap::NG::Common::Conf::_yamlLock {
my ( $self, $cfgNum ) = @_;
......
......@@ -4,7 +4,7 @@ use strict;
use Mouse;
use Lemonldap::NG::Common::Conf::ReConstants;
our $VERSION = '2.0.0';
our $VERSION = '2.0.3';
sub compactConf {
my ( $self, $conf ) = @_;
......@@ -24,6 +24,7 @@ sub compactConf {
s/^(\w+).*$/lc($1)/e;
s/OpenIDConnect/oidc/i;
$keep{$_} = 1;
if ( $_ eq "ad" ) { $keep{'ldap'} = 1; }
}
}
if ( $keep{choice} ) {
......@@ -33,6 +34,7 @@ sub compactConf {
s/^(\w+).*$/lc($1)/e;
s/OpenIDConnect/oidc/i;
$keep{$_} = 1;
if ( $_ eq "ad" ) { $keep{'ldap'} = 1; }
}
}
}
......
......@@ -296,7 +296,7 @@ sub defaultValues {
'useRedirectOnError' => 1,
'useSafeJail' => 1,
'utotp2fActivation' => 0,
'viewerHiddenPK' => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
'viewerHiddenKeys' => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
'webIDAuthnLevel' => 1,
'webIDExportedVars' => {},
'whatToTrace' => 'uid',
......
......@@ -174,7 +174,7 @@ body{background:#000;color:#fff;padding:10px 50px;font-family:sans-serif;}a{text
<body>
<h1>$title</h1>
<p>$err</p>
<center><a href=\"http://lemonldap-ng.org\">LemonLDAP::NG</a></center>'
<center><a href=\"https://lemonldap-ng.org\">LemonLDAP::NG</a></center>
</body>
</html>";
return [
......
......@@ -58,7 +58,7 @@ sub logLevelInit {
$logger = $class->localConfig->{userLogger} || $logger;
eval "require $logger";
die $@ if ($@);
$class->userLogger( $logger->new( $class->localConfig ), user => 1 );
$class->userLogger( $logger->new( $class->localConfig, user => 1 ) );
$class->logger->debug("User logger $logger loaded");
}
......
......@@ -780,7 +780,11 @@ sub postInputFilter {
my %data =
$class->tsv->{inputPostData}->{$vhost}->{$uri}->( $req, $session );
foreach ( keys %data ) {
$data{$_} = uri_escape( $data{$_} );
my $post_key = uri_escape($_);
my $post_value = uri_escape( $data{$_} );
delete $data{$_};
$data{$post_key} = $post_value;
$class->logger->debug("Send key $post_key with value $post_value");
}
$class->setPostParams( $req, \%data );
}
......@@ -809,7 +813,8 @@ sub postJavascript {
: "form.submit();\n";
my $jqueryUrl = $formParams->{jqueryUrl} || "";
$jqueryUrl = &{ $class->tsv->{portal} } . "skins/common/js/jquery-1.10.2.js"
$jqueryUrl =
&{ $class->tsv->{portal} } . "static/bwr/jquery/dist/jquery.min.js"
if ( $jqueryUrl eq "default" );
$jqueryUrl = "<script type='text/javascript' src='$jqueryUrl'></script>\n"
if ($jqueryUrl);
......
......@@ -37,6 +37,7 @@ site/coffee/llApp.coffee
site/coffee/manager.coffee
site/coffee/notifications.coffee
site/coffee/sessions.coffee
site/coffee/viewDiff.coffee
site/coffee/viewer.coffee
site/htdocs/manager.fcgi
site/htdocs/manager.psgi
......@@ -105,6 +106,7 @@ site/htdocs/static/forms/file.html
site/htdocs/static/forms/grant.html
site/htdocs/static/forms/grantContainer.html
site/htdocs/static/forms/home.html
site/htdocs/static/forms/homeViewer.html
site/htdocs/static/forms/int.html
site/htdocs/static/forms/keyText.html
site/htdocs/static/forms/keyTextContainer.html
......@@ -158,6 +160,8 @@ site/htdocs/static/js/notifications.js
site/htdocs/static/js/notifications.min.js
site/htdocs/static/js/sessions.js
site/htdocs/static/js/sessions.min.js
site/htdocs/static/js/viewDiff.js
site/htdocs/static/js/viewDiff.min.js
site/htdocs/static/js/viewer.js
site/htdocs/static/js/viewer.min.js
site/htdocs/static/languages/ar.json
......@@ -191,6 +195,7 @@ site/templates/notifications.tpl
site/templates/scripts.tpl
site/templates/sessions.tpl
site/templates/tree.tpl
site/templates/viewDiff.tpl
site/templates/viewer.tpl
t/02-HTML-template.t
t/03-HTML-forms.t
......@@ -207,6 +212,8 @@ t/40-sessions.t
t/50-notifications-DBI.t
t/50-notifications.t
t/60-2ndfa.t
t/70-viewer.t
t/71-viewer-with-no-diff.t
t/80-attributes.t
t/90-translations.t
t/99-pod.t
......@@ -217,6 +224,8 @@ t/jsonfiles/11-modified-with-confirmation.json
t/jsonfiles/12-modified.json
t/jsonfiles/14-bad.json
t/jsonfiles/15-combination.json
t/jsonfiles/70-diff.json
t/lemonldap-ng-dbi.ini
t/lemonldap-ng-noDiff.ini
t/lemonldap-ng.ini
t/test-lib.pm
......@@ -17,13 +17,14 @@ use JSON;
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Common::PSGI::Constants;
our $VERSION = '2.0.2';
our $VERSION = '2.0.3';
extends 'Lemonldap::NG::Common::Conf::AccessLib',
'Lemonldap::NG::Handler::PSGI::Router';
has csp => ( is => 'rw' );
has brw => ( is => 'rw', default => 0 );
has dif => ( is => 'rw', default => 0 );
## @method boolean init($args)
# Launch initialization method
......@@ -87,7 +88,8 @@ sub init {
$self->csp(
"default-src 'self' $portal;frame-ancestors 'none';form-action 'self';"
);
$self->brw( $conf->{viewerAllowBrowser} );
$self->brw( $self->{viewerAllowBrowser} || $conf->{viewerAllowBrowser} );
$self->dif( $self->{viewerAllowDiff} || $conf->{viewerAllowDiff} );
$self->defaultRoute( $working[0]->defaultRoute );
# Find out more glyphicones at https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp
......@@ -142,6 +144,7 @@ sub javascript {
my ($self) = @_;
return
'var formPrefix=staticPrefix+"forms/";var confPrefix=scriptname+"confs/";var viewPrefix=scriptname+"view/";'
. 'var allowDiff=' . $self->dif . ';'
. ( $self->links ? 'var links=' . to_json( $self->links ) . ';' : '' )
. (
$self->menuLinks
......
......@@ -835,6 +835,10 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'k' => 'LDAP',
'v' => 'LDAP'
},
{
'k' => 'LinkedIn',
'v' => 'LinkedIn'
},
{
'k' => 'PAM',
'v' => 'PAM'
......@@ -3562,7 +3566,11 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
'default' => 0,
'type' => 'bool'
},
'viewerHiddenPK' => {
'viewerAllowDiff' => {
'default' => 0,
'type' => 'bool'
},
'viewerHiddenKeys' => {
'default' => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
'type' => 'text'
},
......
......@@ -916,16 +916,21 @@ sub attributes {
},
# Viewer
viewerHiddenPK => {
viewerHiddenKeys => {
type => 'text',
default => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
documentation => 'ConfTree hidden primary keys',
documentation => 'Hidden Conf keys',
flags => 'm',
},
viewerAllowBrowser => {
type => 'bool',
default => 0,
documentation => 'Allow configuration browser',
type => 'bool',
default => 0,
documentation => 'Allow configuration browser',
},
viewerAllowDiff => {
type => 'bool',
default => 0,
documentation => 'Allow configuration diff',
},
# Notification
......@@ -3108,6 +3113,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
{ k => 'GPG', v => 'GPG' },
{ k => 'Kerberos', v => 'Kerberos' },
{ k => 'LDAP', v => 'LDAP' },
{ k => 'LinkedIn', v => 'LinkedIn' },
{ k => 'PAM', v => 'PAM' },
{ k => 'Radius', v => 'Radius' },
{ k => 'REST', v => 'REST' },
......
package Lemonldap::NG::Manager::Conf::Zero;
our $VERSION = '2.0.2';
our $VERSION = '2.0.3';
sub zeroConf {
my ( $domain, $sessionDir, $persistentSessionDir, $notificationDir ) = @_;
......@@ -147,6 +147,11 @@ sub zeroConf {
'portal' => "http://auth.$domain/",
'notificationStorage' => 'File',
'locationRules' => {
"auth.$domain" => {
'(?#checkUser)^/checkuser' => '$uid eq "dwho"',
'(?#errors)^/lmerror/' => 'accept',
'default' => 'accept'
},
"test1.$domain" => {
'default' => 'accept',
'^/logout' => 'logout_sso'
......@@ -157,7 +162,7 @@ sub zeroConf {
},
"manager.$domain" => {
'default' => '$uid eq "dwho" or $uid eq "rtyler"',
'(?#Configuration)^/(manager\.html|conf/)' => '$uid eq "dwho"',
'(?#Configuration)^/(manager\.html|$)' => '$uid eq "dwho"',
'(?#Sessions)/sessions' => '$uid eq "dwho" or $uid eq "rtyler"',
'(?#Notifications)/notifications' =>
'$uid eq "dwho" or $uid eq "rtyler"',
......
# This module implements all the methods that responds to '/confs/*' requests
# It contains 2 sections:
# - initialization methods
# - upload method
#
# Read methods are inherited from Lemonldap::NG::Common::Conf::RESTServer
package Lemonldap::NG::Manager::Viewer;
use 5.10.0;
......@@ -31,6 +25,8 @@ sub addRoutes {
my ( $self, $conf ) = @_;
$self->ua( Lemonldap::NG::Common::UserAgent->new($conf) );
my $hiddenPK = '';
$hiddenPK = $self->{viewerHiddenKeys} || $conf->{viewerHiddenKeys};
my @enabledPK = ();
my @keys = qw(virtualHosts samlIDPMetaDataNodes samlSPMetaDataNodes
applicationList oidcOPMetaDataNodes oidcRPMetaDataNodes
......@@ -42,7 +38,7 @@ sub addRoutes {
# Ignore hidden ConfTree Primary Keys
push @enabledPK, $_
unless ( $self->{viewerHiddenPK} =~ /\b$_\b/ );
unless ( $hiddenPK =~ /\b$_\b/ );
}
# HTML template
......@@ -57,19 +53,28 @@ sub addRoutes {
['GET']
);
foreach ( split /\s+/, $self->{viewerHiddenPK} ) {
foreach ( split /\s+/, $hiddenPK ) {
$self->addRoute(
view => { ':cfgNum' => { $_ => 'rejectKey' } },
['GET']
);
}
unless ( $self->{viewerAllowBrowser} || $conf->{viewerAllowBrowser} ) {
$self->addRoute(
view => { ':cfgNum' => 'rejectKey' },
['GET']
);
}
# Other keys
$self->addRoute( view => { ':cfgNum' => { '*' => 'getKey' } }, ['GET'] )
# Difference between confs
if ( $self->{viewerAllowDiff} || $conf->{viewerAllowDiff} ) {
$self->addRoute(
view => { diff => { ':conf1' => { ':conf2' => 'viewDiff' } } } )
->addRoute( 'viewDiff.html', undef, ['GET'] );
}
# Difference between confs
->addRoute( diff => { ':conf1' => { ':conf2' => 'diff' } } )
->addRoute( 'diff.html', undef, ['GET'] );
# Other keys
$self->addRoute( view => { ':cfgNum' => { '*' => 'getKey' } }, ['GET'] );
}
sub getConfByNum {
......@@ -77,9 +82,43 @@ sub getConfByNum {
$self->SUPER::getConfByNum( $cfgNum, @args );
}
sub diff {
sub viewDiff {
my ( $self, $req, @path ) = @_;
$self->SUPER::diff( $req, @path );
return $self->sendError( $req, 'to many arguments in path info', 400 )
if (@path);
my @cfgNum =
( scalar( $req->param('conf1') ), scalar( $req->param('conf2') ) );
my @conf;
$self->logger->debug(" Loading confs");
# Load the 2 configurations
for ( my $i = 0 ; $i < 2 ; $i++ ) {
if ( %{ $self->currentConf }
and $cfgNum[$i] == $self->currentConf->{cfgNum} )
{
$conf[$i] = $self->currentConf;
}
else {
$conf[$i] = $self->confAcc->getConf(
{ cfgNum => $cfgNum[$i], raw => 1, noCache => 1 } );
return $self->sendError(
$req,
"Configuration $cfgNum[$i] not available $Lemonldap::NG::Common::Conf::msg",
400
) unless ( $conf[$i] );
}
}
require Lemonldap::NG::Manager::Conf::Diff;
my @res =
$self->Lemonldap::NG::Manager::Conf::Diff::diff( $conf[0], $conf[1] );
my $hiddenKeys = $self->{viewerHiddenKeys} || '';
$self->logger->debug("Deleting hidden Conf keys...");
foreach ( split /\s+/, $hiddenKeys ) {
$self->logger->debug("-> Delete $_");
delete $res[0]->{$_};
delete $res[1]->{$_};
}
return $self->sendJSONresponse( $req, [@res] );
}
sub rejectKey {
......
......@@ -179,8 +179,6 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
# Session preparation
transformSession = (session) ->
_stToStr = (s) ->
s
_insert = (re, title) ->
tmp = []
reg = new RegExp(re)
......@@ -210,10 +208,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
else if key.match /^(_utime|_lastAuthnUTime|_lastSeen|notification)$/
session[key] = $scope.localeDate value
else if key.match /^(_startTime|_updateTime)$/
value = _stToStr value
pattern = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/
arrayDate = value.match(pattern)
session[key] = "#{arrayDate[3]}/#{arrayDate[2]}/#{arrayDate[1]} à #{arrayDate[4]}:#{arrayDate[5]}:#{arrayDate[6]}"
session[key] = $scope.strToLocaleDate value
res = []
......@@ -345,6 +340,12 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
d = new Date(s * 1000)
return d.toLocaleString()
$scope.strToLocaleDate = (s) ->
arrayDate = s.match /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/
return s unless arrayDate.length
d = new Date "#{arrayDate[1]}-#{arrayDate[2]}-#{arrayDate[3]}T#{arrayDate[4]}:#{arrayDate[5]}:#{arrayDate[6]}"
return d.toLocaleString()
# Function to change interface language
$scope.getLanguage = (lang) ->
$scope.lang = lang
......
###
diff.html script
###
llapp = angular.module 'llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'] , ($rootScopeProvider) -> $rootScopeProvider.digestTtl(15)
llapp.controller 'DiffCtrl', [ '$scope', '$http', '$q', '$translator', '$location', ($scope, $http, $q, $translator, $location) ->
$scope.links = links
$scope.menulinks = menulinks
$scope.staticPrefix = staticPrefix
$scope.scriptname = scriptname
#$scope.formPrefix = formPrefix
$scope.availableLanguages = availableLanguages
$scope.waiting = true
$scope.showM = false
$scope.cfg = []
$scope.data = {}
$scope.currentNode = null
# Import translations functions
$scope.translateTitle = (node) ->
return $translator.translateField node, 'title'
$scope.translateP = $translator.translateP
$scope.translate = $translator.translate
$scope.toggle = (scope) ->
scope.toggle()
$scope.stoggle = (scope,node) ->
$scope.currentNode = node
scope.toggle()
# Handle menu items
$scope.menuClick = (button) ->
if button.popup
window.open button.popup
else
button.action = button.title unless button.action
switch typeof button.action
when 'function'
button.action $scope.currentNode, $scope
when 'string'
$scope[button.action]()
else
console.log typeof button.action
$scope.showM = false
# Function to change interface language
$scope.getLanguage = (lang) ->
$scope.lang = lang
$scope.init()
$scope.showM = false
# function `getCfg(b,n)`:
# Download configuration metadatas
#
#@param b local conf (0 or 1)
#@param n cfgNumber
getCfg = (b,n) ->
d = $q.defer()
if not $scope.cfg[b]? or $scope.cfg[b] != n
$http.get("#{confPrefix}#{n}").then (response) ->
if response and response.data
$scope.cfg[b] = response.data
date = new Date response.data.cfgDate * 1000
$scope.cfg[b].date = date.toLocaleString()
console.log "Metadatas of cfg #{n} loaded"
d.resolve 'OK'
else
d.reject response
, (response) ->
console.log response
d.reject 'NOK'
else
d.resolve()
return d.promise
# Intialization function
# Simply set $scope.waiting to false during $translator and tree root
# initialization
init = ->
$scope.message = null
$scope.currentNode = null
d = $q.defer()
$http.get("#{scriptname}view/diff/#{$scope.cfg[0].cfgNum}/#{$scope.cfg[1].cfgNum}").then (response) ->
data = []
data = readDiff(response.data[0],response.data[1])
$scope.data = buildTree(data)
$scope.message = ''
$scope.waiting = false
, (response) ->
$scope.message = "#{$scope.translate('error')} : #{response.statusLine}"
readDiff = (c1,c2,tr=true) ->
res = []
for k,v of c1
if tr
tmp =
title: $scope.translate(k)
id: k
else
tmp = title: k
unless k.match /^cfg(?:Num|Log|Author(?:IP)?|Date)$/
if v? and typeof v == 'object'
if v.constructor == 'array'
tmp.oldvalue = v
tmp.newvalue = c2[k]
else if typeof c2[k] == 'object'
tmp.nodes = readDiff c1[k],c2[k], false
else
tmp.oldnodes = toNodes v, 'old'
else
tmp.oldvalue = v
tmp.newvalue = c2[k]
res.push tmp
for k,v of c2
unless (k.match /^cfg(?:Num|Log|Author(?:IP)?|Date)$/) or c1[k]?
if tr
tmp =
title: $scope.translate(k)
id: k
else
tmp = title: k
if v? and typeof v == 'object'
if v.constructor == 'array'
tmp.newvalue = v
else
console.log "Iteration"
tmp.newnodes = toNodes v, 'new'
else
tmp.newvalue = v
res.push tmp
return res
toNodes = (c,s) ->
res = []
for k,v of c
tmp = title:k
if typeof v == 'object'
if v.constructor == 'array'
tmp["#{s}value"] = v
else
tmp["#{s}nodes"] = toNodes c[k], s
else
tmp["#{s}value"] = v
res.push tmp
return res
reverseTree = []
buildTree = (data) ->
return data unless reverseTree?
res = []
for elem in data
offset = res
path = if reverseTree[elem.id]? then reverseTree[elem.id].split '/' else ''
for node in path
if node.length > 0
if offset.length
found = -1
for n,i in offset
if n.id == node
#offset = n.nodes
found = i
if found != -1
offset = offset[found].nodes
else
offset.push
id: node
title: $scope.translate node
nodes: []
offset = offset[offset.length-1].nodes
else
offset.push
id: node
title: $scope.translate node
nodes: []
offset = offset[0].nodes
offset.push elem
return res
$scope.newDiff = ->
$location.path("/#{$scope.cfg[0].cfgNum}/#{$scope.cfg[1].cfgNum}")
pathEvent = (event, next, current) ->
n = next.match(new RegExp('#!?/(latest|[0-9]+)(?:/(latest|[0-9]+))?$'))
if n == null
$location.path '/latest'
else
$scope.waiting = true
$q.all [
$translator.init $scope.lang
$http.get("#{staticPrefix}reverseTree.json").then (response) ->
reverseTree = response.data
console.log "Structure loaded"
getCfg 0, n[1]
getCfg 1, n[2] if n[2]?
]
.then ->
if n[2]?
init()
else
if $scope.cfg[0].prev
$scope.cfg[1] = $scope.cfg[0]
getCfg 0, $scope.cfg[1].prev
.then ->
init()
else
$scope.data = []
$scope.waiting = false
, ->
$scope.message = $scope.translate('error')
$scope.waiting = false
true
$scope.$on '$locationChangeSuccess', pathEvent
]
......@@ -27,9 +27,10 @@ llapp.controller 'TreeCtrl', [
$scope.waiting = true
$scope.showM = false
$scope.showT = false
$scope.form = 'home'
$scope.form = 'homeViewer'
$scope.currentCfg = {}
$scope.viewPrefix = window.viewPrefix
$scope.allowDiff = window.allowDiff
$scope.message = {}
$scope.result = ''
......@@ -133,38 +134,9 @@ llapp.controller 'TreeCtrl', [
# Display main form
$scope.home = ->
$scope.form = 'home'
$scope.form = 'homeViewer'
$scope.showM = false
# SAVE FUNCTIONS
# # Private method called by $scope.save()
# _checkSaveResponse = (data) ->
# $scope.message =
# title: ''
# message: ''
# items: []
# $scope.confirmNeeded = true if data.needConfirm
# $scope.message.message = data.message if data.message
# if data.details
# for m of data.details when m != '__changes__'
# if m == '__needConfirmation__'
# $scope.message.items.unshift
# message: m
# items: data.details[m]
# else
# $scope.message.items.push
# message: m
# items: data.details[m]
# $scope.waiting = false
# if data.result == 1
# # Force reloading page
# $location.path '/confs/'
# $scope.message.title = 'successfullySaved'
# else
# $scope.message.title = 'saveReport'
# $scope.showModal 'message.html'
# Download raw conf
$scope.downloadConf = () ->
window.open $scope.viewPrefix + $scope.currentCfg.cfgNum + '?full=1'
......@@ -379,6 +351,9 @@ llapp.controller 'TreeCtrl', [
node.data = node['default']
else
node.data = data.value
if node.data.toString().match /_Hidden_$/
node.type = 'text'
node.data = '######'
# Cast int as int (remember that booleans are int for Perl)
if node.type and node.type.match /^int$/
node.data = parseInt(node.data, 10)
......@@ -391,6 +366,9 @@ llapp.controller 'TreeCtrl', [
readError response
d.reject response.status
else
if node.data.toString().match /_Hidden_$/
node.type = 'text'
node.data = '######'
d.resolve node.data
return d.promise
......@@ -461,7 +439,7 @@ llapp.controller 'TreeCtrl', [
title: 'emptyConf'
message: '__zeroConfExplanations__'
$scope.showModal 'message.html'
$scope.form = 'home'
$scope.form = 'homeViewer'
$scope.waiting = false
, readError
# Colorized link
......
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<span ng-if="!currentCfg.next" trspan="currentConfiguration"></span>
<span ng-if="currentCfg.next" trspan="loadedConfiguration"></span>
<i ng-if="currentCfg.prev && allowDiff">(<a trspan="diffWithPrevious" target="_blank" href="{{scriptname}}/viewDiff.html#!/{{currentCfg.cfgNum}}" role="link"></a>)</i>
</h3>
</div>
<table class="table table-striped">
<tr>
<th><span trspan="number"></span></th>
<td>
<span id="cfgnum" class="label label-success" comment="{{translateP('__newCfgAvailable__')}}" ng-class="{'label-warning':currentCfg.next}">{{currentCfg.cfgNum}}</span>
</td>
</tr>
<tr ng-if="currentCfg.cfgAuthor">
<th><span trspan="author"></span></th>
<td>{{currentCfg.cfgAuthor}}</td>
</tr>
<tr ng-if="currentCfg.cfgAuthorIP">
<th><span trspan="authorIPAddress"></span></th>
<td>{{currentCfg.cfgAuthorIP}}</td>
</tr>
<tr ng-if="currentCfg.cfgDate">
<th><span trspan="date"></span></th>
<td>{{currentCfg.date}}</td>
</tr>
<tr ng-if="currentCfg.cfgVersion">
<th><span trspan="cfgVersion"></span></th>
<td>{{currentCfg.cfgVersion}}</td>
</tr>
<tr ng-if="currentCfg.cfgLog">
<th><span trspan="cfgLog"></span></th>
<td id="cfglog">{{currentCfg.cfgLog}}</td>
</tr>
</table>
</div>
<script type="text/menu">
[{
"title": "downloadIt",
"action": "downloadConf",
"icon": "export"
},{
"title": "restore",
"icon": "import"
}]
</script>
......@@ -28,7 +28,7 @@
<td ng-if="n.type=='bool'">
<div class="input-group-solid" role="radiogroup">
<label class="radio-inline">
<input id="bopeOn/{{n.title}}" type="radio" ng-value="1" ng-model="n.data" role="radio" aria-labelledby="lbopeOn{{n.title}}"/>
<input id="bopeOn/{{n.title}}" type="radio" ng-value="1" ng-model="n.data" ng-checked="n.data==1||n.data=='1'" role="radio" aria-labelledby="lbopeOn{{n.title}}"/>
<span id="lbopeOn{{n.title}}" for="bopeOn/{{n.title}}" trspan="on"></span>
</label>
<label class="radio-inline">
......
// Generated by CoffeeScript 1.12.7
// Generated by CoffeeScript 1.12.8
/*
* 2ndFA Session explorer
......
// Generated by CoffeeScript 1.12.7
// Generated by CoffeeScript 1.12.8
/*
diff.html script
......
// Generated by CoffeeScript 1.12.7
// Generated by CoffeeScript 1.12.8
(function() {
var filterFunctions;
......
// Generated by CoffeeScript 1.12.7
// Generated by CoffeeScript 1.12.8
/*
* LemonLDAP::NG Notifications Explorer client
......
......@@ -199,10 +199,7 @@
$scope.displaySession = function(scope) {
var sessionId, transformSession;
transformSession = function(session) {
var _insert, _stToStr, array, arrayDate, attr, attrs, category, cv, epoch, i, id, j, k, key, l, len, len1, len2, len3, len4, m, name, o, oidcConsent, pattern, ref, ref1, res, sfDevice, subres, time, title, tmp, value;
_stToStr = function(s) {
return s;
};
var _insert, array, attr, attrs, category, cv, epoch, i, id, j, k, key, l, len, len1, len2, len3, len4, m, name, o, oidcConsent, ref, ref1, res, sfDevice, subres, time, title, tmp, value;
_insert = function(re, title) {
var key, reg, tmp, value;
tmp = [];
......@@ -240,10 +237,7 @@
} else if (key.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)) {
session[key] = $scope.localeDate(value);
} else if (key.match(/^(_startTime|_updateTime)$/)) {
value = _stToStr(value);
pattern = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/;
arrayDate = value.match(pattern);
session[key] = arrayDate[3] + "/" + arrayDate[2] + "/" + arrayDate[1] + " à " + arrayDate[4] + ":" + arrayDate[5] + ":" + arrayDate[6];
session[key] = $scope.strToLocaleDate(value);
}
}
}
......@@ -424,6 +418,15 @@
d = new Date(s * 1000);
return d.toLocaleString();
};
$scope.strToLocaleDate = function(s) {
var arrayDate, d;
arrayDate = s.match(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/);
if (!arrayDate.length) {
return s;
}
d = new Date(arrayDate[1] + "-" + arrayDate[2] + "-" + arrayDate[3] + "T" + arrayDate[4] + ":" + arrayDate[5] + ":" + arrayDate[6]);
return d.toLocaleString();
};
$scope.getLanguage = function(lang) {
$scope.lang = lang;
$scope.form = 'white';
......
(function(){var categories,hiddenAttributes,llapp,max,menu,overScheme,schemes;max=25;schemes={_whatToTrace:[function(t,v){return"groupBy=substr("+t+",1)"},function(t,v){return t+"="+v+"*&groupBy="+t},function(t,v){return t+"="+v}],ipAddr:[function(t,v){return"groupBy=net("+t+",16,1)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",32,2)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",48,3)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",128,4)"},function(t,v){return t+"="+v+"&groupBy=_whatToTrace"},function(t,v,q){return q.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+v)}],_startTime:[function(t,v){return"groupBy=substr("+t+",8)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",10)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",11)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",12)"},function(t,v){return t+"="+v+"*&groupBy=_whatToTrace"},function(t,v,q){console.log(t);console.log(v);console.log(q);return q.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+v)}],doubleIp:[function(t,v){return t},function(t,v){return"_whatToTrace="+v+"&groupBy=ipAddr"},function(t,v,q){return q.replace(/\&groupBy.*$/,"")+("&ipAddr="+v)}]};overScheme={_whatToTrace:function(t,v,level,over){if(level===1&&v.length>over){return t+"="+v+"*&groupBy=substr("+t+","+(level+over+1)+")"}else{return null}},ipAddr:function(t,v,level,over){if(level>0&&level<4){return t+"="+v+"*&groupBy=net("+t+","+(16*level+4*(over+1))+",2)"}else{return null}}};hiddenAttributes="_password";categories={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"],sfaTitle:["_2fDevices"],oidcConsents:["_oidcConsents"]};menu={session:[{title:"deleteSession",icon:"trash"}],home:[]};llapp=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);llapp.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function($scope,$translator,$location,$q,$http){var autoId,c,pathEvent,sessionType;$scope.links=links;$scope.menulinks=menulinks;$scope.staticPrefix=staticPrefix;$scope.scriptname=scriptname;$scope.formPrefix=formPrefix;$scope.availableLanguages=availableLanguages;$scope.waiting=true;$scope.showM=false;$scope.showT=true;$scope.data=[];$scope.currentScope=null;$scope.currentSession=null;$scope.menu=menu;$scope.translateP=$translator.translateP;$scope.translate=$translator.translate;$scope.translateTitle=function(node){return $translator.translateField(node,"title")};sessionType="global";$scope.menuClick=function(button){if(button.popup){window.open(button.popup)}else{if(!button.action){button.action=button.title}switch(typeof button.action){case"function":button.action($scope.currentNode,$scope);break;case"string":$scope[button.action]();break;default:console.log(typeof button.action)}}return $scope.showM=false};$scope.deleteOIDCConsent=function(rp,epoch){var item;item=angular.element(".data-"+epoch);item.remove();$scope.waiting=true;$http["delete"](scriptname+"sessions/OIDCConsent/"+sessionType+"/"+$scope.currentSession.id+"?rp="+rp+"&epoch="+epoch).then(function(response){return $scope.waiting=false},function(resp){return $scope.waiting=false});return $scope.showT=false};$scope.deleteSession=function(){$scope.waiting=true;return $http["delete"](scriptname+"sessions/"+sessionType+"/"+$scope.currentSession.id).then(function(response){$scope.currentSession=null;$scope.currentScope.remove();return $scope.waiting=false},function(resp){$scope.currentSession=null;$scope.currentScope.remove();return $scope.waiting=false})};$scope.stoggle=function(scope){var node;node=scope.$modelValue;if(node.nodes.length===0){$scope.updateTree(node.value,node.nodes,node.level,node.over,node.query,node.count)}return scope.toggle()};$scope.displaySession=function(scope){var sessionId,transformSession;transformSession=function(session){var _insert,_stToStr,array,arrayDate,attr,attrs,category,cv,epoch,i,id,j,k,key,l,len,len1,len2,len3,len4,m,name,o,oidcConsent,pattern,ref,ref1,res,sfDevice,subres,time,title,tmp,value;_stToStr=function(s){return s};_insert=function(re,title){var key,reg,tmp,value;tmp=[];reg=new RegExp(re);for(key in session){value=session[key];if(key.match(reg)&&value){tmp.push({title:key,value:value});delete session[key]}}if(tmp.length>0){return res.push({title:title,nodes:tmp})}};time=session._utime;id=session._session_id;for(key in session){value=session[key];if(!value){delete session[key]}else{if(typeof session==="string"&&value.match(/; /)){session[key]=value.split("; ")}if(typeof session[key]!=="object"){if(hiddenAttributes.match(new RegExp("\b"+key+"\b"))){session[key]="********"}else if(key.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){session[key]=$scope.localeDate(value)}else if(key.match(/^(_startTime|_updateTime)$/)){value=_stToStr(value);pattern=/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/;arrayDate=value.match(pattern);session[key]=arrayDate[3]+"/"+arrayDate[2]+"/"+arrayDate[1]+" à "+arrayDate[4]+":"+arrayDate[5]+":"+arrayDate[6]}}}}res=[];for(category in categories){attrs=categories[category];subres=[];for(i=0,len=attrs.length;i<len;i++){attr=attrs[i];if(session[attr]){if(session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK)"/)){subres.push({title:"type",value:"name",epoch:"date",td:"0"});array=JSON.parse(session[attr]);for(j=0,len1=array.length;j<len1;j++){sfDevice=array[j];for(key in sfDevice){value=sfDevice[key];if(key==="type"){title=value}if(key==="name"){name=value}if(key==="epoch"){epoch=value}}subres.push({title:title,value:name,epoch:epoch,td:"1"})}delete session[attr]}else if(session[attr].toString().match(/"rp":\s*"[\w-]+"/)){subres.push({title:"rp",value:"scope",epoch:"date",td:"0"});array=JSON.parse(session[attr]);for(k=0,len2=array.length;k<len2;k++){oidcConsent=array[k];for(key in oidcConsent){value=oidcConsent[key];if(key==="rp"){title=value}if(key==="scope"){name=value}if(key==="epoch"){epoch=value}}subres.push({title:title,value:name,epoch:epoch,td:"2"})}delete session[attr]}else if(session[attr].toString().match(/\w+/)){subres.push({title:attr,value:session[attr],epoch:""});delete session[attr]}else{delete session[attr]}}else{delete session[attr]}}if(subres.length>0){res.push({title:"__"+category+"__",nodes:subres})}}_insert("^openid","OpenID");_insert("^notification_(.+)","__notificationsDone__");if(session._loginHistory){tmp=[];if(session._loginHistory.successLogin){ref=session._loginHistory.successLogin;for(m=0,len3=ref.length;m<len3;m++){l=ref[m];cv="";for(key in l){value=l[key];if(!key.match(/^(_utime|ipAddr|error)$/)){cv+=", "+key+" : "+value}}tmp.push({t:l._utime,title:$scope.localeDate(l._utime),value:"Success (IP "+l.ipAddr+")"+cv})}}if(session._loginHistory.failedLogin){ref1=session._loginHistory.failedLogin;for(o=0,len4=ref1.length;o<len4;o++){l=ref1[o];cv="";for(key in l){value=l[key];if(!key.match(/^(_utime|ipAddr|error)$/)){cv+=", "+key+" : "+value}}tmp.push({t:l._utime,title:$scope.localeDate(l._utime),value:"Error "+l.error+" (IP "+l.ipAddr+")"+cv})}}delete session._loginHistory;tmp.sort(function(a,b){return b.t-a.t});res.push({title:"__loginHistory__",nodes:tmp})}tmp=[];for(key in session){value=session[key];tmp.push({title:key,value:value})}tmp.sort(function(a,b){if(a.title>b.title){return 1}else if(a.title<b.title){return-1}else{return 0}});res.push({title:"__attributesAndMacros__",nodes:tmp});return{_utime:time,id:id,nodes:res}};$scope.currentScope=scope;sessionId=scope.$modelValue.session;$http.get(scriptname+"sessions/"+sessionType+"/"+sessionId).then(function(response){return $scope.currentSession=transformSession(response.data)});return $scope.showT=false};$scope.localeDate=function(s){var d;d=new Date(s*1e3);return d.toLocaleString()};$scope.getLanguage=function(lang){$scope.lang=lang;$scope.form="white";$scope.init();return $scope.showM=false};pathEvent=function(event,next,current){var n;n=next.match(/#!?\/(\w+)/);sessionType="global";if(n===null){$scope.type="_whatToTrace"}else if(n[1].match(/^(persistent)$/)){sessionType=RegExp.$1;$scope.type="_session_uid"}else{$scope.type=n[1]}return $scope.init()};$scope.$on("$locationChangeSuccess",pathEvent);autoId=0;$scope.updateTree=function(value,node,level,over,currentQuery,count){var query,scheme,tmp;$scope.waiting=true;scheme=schemes[$scope.type]?schemes[$scope.type]:$scope.type==="_updateTime"?schemes._startTime:schemes._whatToTrace;query=scheme[level]($scope.type,value,currentQuery);if(count>max&&overScheme[$scope.type]){if(tmp=overScheme[$scope.type]($scope.type,value,level,over,currentQuery)){over++;query=tmp;level=level-1}else{over=0}}else{over=0}return $http.get(scriptname+"sessions/"+sessionType+"?"+query).then(function(response){var data,i,len,n,ref;data=response.data;if(data.result){ref=data.values;for(i=0,len=ref.length;i<len;i++){n=ref[i];autoId++;n.id="node"+autoId;if(level<scheme.length-1){n.nodes=[];n.level=level+1;n.query=query;n.over=over;if($scope.type.match(/^(?:start|update)Time$/)){n.title=n.value.replace(/^(\d{8})(\d{2})(\d{2})$/,"$2:$3").replace(/^(\d{8})(\d{2})(\d)$/,"$2:$30").replace(/^(\d{8})(\d{2})$/,"$2h").replace(/^(\d{4})(\d{2})(\d{2})/,"$1-$2-$3")}}node.push(n)}if(value===""){$scope.total=data.total}}return $scope.waiting=false},function(resp){return $scope.waiting=false})};$scope.init=function(){$scope.waiting=true;$scope.data=[];$q.all([$translator.init($scope.lang),$scope.updateTree("",$scope.data,0,0)]).then(function(){return $scope.waiting=false},function(resp){return $scope.waiting=false});$scope.activeModule="sessions";return $scope.myStyle={color:"#ffb84d"}};c=$location.path().match(/^\/(\w+)/);return $scope.type=c?c[1]:"_whatToTrace"}])}).call(this);
(function(){var categories,hiddenAttributes,llapp,max,menu,overScheme,schemes;max=25;schemes={_whatToTrace:[function(t,v){return"groupBy=substr("+t+",1)"},function(t,v){return t+"="+v+"*&groupBy="+t},function(t,v){return t+"="+v}],ipAddr:[function(t,v){return"groupBy=net("+t+",16,1)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",32,2)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",48,3)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",128,4)"},function(t,v){return t+"="+v+"&groupBy=_whatToTrace"},function(t,v,q){return q.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+v)}],_startTime:[function(t,v){return"groupBy=substr("+t+",8)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",10)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",11)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",12)"},function(t,v){return t+"="+v+"*&groupBy=_whatToTrace"},function(t,v,q){console.log(t);console.log(v);console.log(q);return q.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+v)}],doubleIp:[function(t,v){return t},function(t,v){return"_whatToTrace="+v+"&groupBy=ipAddr"},function(t,v,q){return q.replace(/\&groupBy.*$/,"")+("&ipAddr="+v)}]};overScheme={_whatToTrace:function(t,v,level,over){if(level===1&&v.length>over){return t+"="+v+"*&groupBy=substr("+t+","+(level+over+1)+")"}else{return null}},ipAddr:function(t,v,level,over){if(level>0&&level<4){return t+"="+v+"*&groupBy=net("+t+","+(16*level+4*(over+1))+",2)"}else{return null}}};hiddenAttributes="_password";categories={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"],sfaTitle:["_2fDevices"],oidcConsents:["_oidcConsents"]};menu={session:[{title:"deleteSession",icon:"trash"}],home:[]};llapp=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);llapp.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function($scope,$translator,$location,$q,$http){var autoId,c,pathEvent,sessionType;$scope.links=links;$scope.menulinks=menulinks;$scope.staticPrefix=staticPrefix;$scope.scriptname=scriptname;$scope.formPrefix=formPrefix;$scope.availableLanguages=availableLanguages;$scope.waiting=true;$scope.showM=false;$scope.showT=true;$scope.data=[];$scope.currentScope=null;$scope.currentSession=null;$scope.menu=menu;$scope.translateP=$translator.translateP;$scope.translate=$translator.translate;$scope.translateTitle=function(node){return $translator.translateField(node,"title")};sessionType="global";$scope.menuClick=function(button){if(button.popup){window.open(button.popup)}else{if(!button.action){button.action=button.title}switch(typeof button.action){case"function":button.action($scope.currentNode,$scope);break;case"string":$scope[button.action]();break;default:console.log(typeof button.action)}}return $scope.showM=false};$scope.deleteOIDCConsent=function(rp,epoch){var item;item=angular.element(".data-"+epoch);item.remove();$scope.waiting=true;$http["delete"](scriptname+"sessions/OIDCConsent/"+sessionType+"/"+$scope.currentSession.id+"?rp="+rp+"&epoch="+epoch).then(function(response){return $scope.waiting=false},function(resp){return $scope.waiting=false});return $scope.showT=false};$scope.deleteSession=function(){$scope.waiting=true;return $http["delete"](scriptname+"sessions/"+sessionType+"/"+$scope.currentSession.id).then(function(response){$scope.currentSession=null;$scope.currentScope.remove();return $scope.waiting=false},function(resp){$scope.currentSession=null;$scope.currentScope.remove();return $scope.waiting=false})};$scope.stoggle=function(scope){var node;node=scope.$modelValue;if(node.nodes.length===0){$scope.updateTree(node.value,node.nodes,node.level,node.over,node.query,node.count)}return scope.toggle()};$scope.displaySession=function(scope){var sessionId,transformSession;transformSession=function(session){var _insert,array,attr,attrs,category,cv,epoch,i,id,j,k,key,l,len,len1,len2,len3,len4,m,name,o,oidcConsent,ref,ref1,res,sfDevice,subres,time,title,tmp,value;_insert=function(re,title){var key,reg,tmp,value;tmp=[];reg=new RegExp(re);for(key in session){value=session[key];if(key.match(reg)&&value){tmp.push({title:key,value:value});delete session[key]}}if(tmp.length>0){return res.push({title:title,nodes:tmp})}};time=session._utime;id=session._session_id;for(key in session){value=session[key];if(!value){delete session[key]}else{if(typeof session==="string"&&value.match(/; /)){session[key]=value.split("; ")}if(typeof session[key]!=="object"){if(hiddenAttributes.match(new RegExp("\b"+key+"\b"))){session[key]="********"}else if(key.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){session[key]=$scope.localeDate(value)}else if(key.match(/^(_startTime|_updateTime)$/)){session[key]=$scope.strToLocaleDate(value)}}}}res=[];for(category in categories){attrs=categories[category];subres=[];for(i=0,len=attrs.length;i<len;i++){attr=attrs[i];if(session[attr]){if(session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK)"/)){subres.push({title:"type",value:"name",epoch:"date",td:"0"});array=JSON.parse(session[attr]);for(j=0,len1=array.length;j<len1;j++){sfDevice=array[j];for(key in sfDevice){value=sfDevice[key];if(key==="type"){title=value}if(key==="name"){name=value}if(key==="epoch"){epoch=value}}subres.push({title:title,value:name,epoch:epoch,td:"1"})}delete session[attr]}else if(session[attr].toString().match(/"rp":\s*"[\w-]+"/)){subres.push({title:"rp",value:"scope",epoch:"date",td:"0"});array=JSON.parse(session[attr]);for(k=0,len2=array.length;k<len2;k++){oidcConsent=array[k];for(key in oidcConsent){value=oidcConsent[key];if(key==="rp"){title=value}if(key==="scope"){name=value}if(key==="epoch"){epoch=value}}subres.push({title:title,value:name,epoch:epoch,td:"2"})}delete session[attr]}else if(session[attr].toString().match(/\w+/)){subres.push({title:attr,value:session[attr],epoch:""});delete session[attr]}else{delete session[attr]}}else{delete session[attr]}}if(subres.length>0){res.push({title:"__"+category+"__",nodes:subres})}}_insert("^openid","OpenID");_insert("^notification_(.+)","__notificationsDone__");if(session._loginHistory){tmp=[];if(session._loginHistory.successLogin){ref=session._loginHistory.successLogin;for(m=0,len3=ref.length;m<len3;m++){l=ref[m];cv="";for(key in l){value=l[key];if(!key.match(/^(_utime|ipAddr|error)$/)){cv+=", "+key+" : "+value}}tmp.push({t:l._utime,title:$scope.localeDate(l._utime),value:"Success (IP "+l.ipAddr+")"+cv})}}if(session._loginHistory.failedLogin){ref1=session._loginHistory.failedLogin;for(o=0,len4=ref1.length;o<len4;o++){l=ref1[o];cv="";for(key in l){value=l[key];if(!key.match(/^(_utime|ipAddr|error)$/)){cv+=", "+key+" : "+value}}tmp.push({t:l._utime,title:$scope.localeDate(l._utime),value:"Error "+l.error+" (IP "+l.ipAddr+")"+cv})}}delete session._loginHistory;tmp.sort(function(a,b){return b.t-a.t});res.push({title:"__loginHistory__",nodes:tmp})}tmp=[];for(key in session){value=session[key];tmp.push({title:key,value:value})}tmp.sort(function(a,b){if(a.title>b.title){return 1}else if(a.title<b.title){return-1}else{return 0}});res.push({title:"__attributesAndMacros__",nodes:tmp});return{_utime:time,id:id,nodes:res}};$scope.currentScope=scope;sessionId=scope.$modelValue.session;$http.get(scriptname+"sessions/"+sessionType+"/"+sessionId).then(function(response){return $scope.currentSession=transformSession(response.data)});return $scope.showT=false};$scope.localeDate=function(s){var d;d=new Date(s*1e3);return