+116
@@ -0,0 +1,116 @@
|
||||
var table;
|
||||
|
||||
$(document).ready(function () {
|
||||
$('#fmrel').on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var username = $('#username').val();
|
||||
var password = $('#password').val();
|
||||
var service = $('#service').val();
|
||||
|
||||
releaseAttributes(username, password, service);
|
||||
});
|
||||
|
||||
|
||||
$('#fm1').on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var uid = $('#uid').val();
|
||||
table = $('#attributesTable').DataTable();
|
||||
table.clear().draw();
|
||||
|
||||
var status = $('#status');
|
||||
|
||||
if (uid !== null && uid !== '') {
|
||||
resolveAttributes(uid);
|
||||
status.html('Resolved attributes for username <strong>' + uid + '</strong>.');
|
||||
status.removeClass('alert-danger');
|
||||
status.addClass('alert-info');
|
||||
status.show();
|
||||
} else {
|
||||
status.html('No username is provided.');
|
||||
status.removeClass('alert-info');
|
||||
status.addClass('alert-danger');
|
||||
status.show();
|
||||
}
|
||||
});
|
||||
|
||||
if ($.fn.dataTable.isDataTable('#attributesTable')) {
|
||||
table = $('#attributesTable').DataTable();
|
||||
} else {
|
||||
table = $('#attributesTable').DataTable({
|
||||
paging: false,
|
||||
searching: false
|
||||
});
|
||||
}
|
||||
|
||||
$('#status').hide();
|
||||
|
||||
});
|
||||
|
||||
function resolveAttributes(uid) {
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
url: urls.resolveAttributes,
|
||||
data: {'uid': uid},
|
||||
success: function (data) {
|
||||
var table = $('#attributesTable').DataTable();
|
||||
table.clear();
|
||||
var attrs = data.attributes;
|
||||
for (var property in attrs) {
|
||||
if (attrs.hasOwnProperty(property)) {
|
||||
table.row.add([
|
||||
'<code>' + property + '</code>', '<code>' + attrs[property] + '</code>'
|
||||
]).draw(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function releaseAttributes(uid, psw, service) {
|
||||
$('validationresponse').empty();
|
||||
$('cas1').empty();
|
||||
$('cas2').empty();
|
||||
$('cas3Xml').empty();
|
||||
$('cas3Json').empty();
|
||||
|
||||
$('#submitRelease').attr('disabled', 'disabled');
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
url: urls.releaseAttributes,
|
||||
data: {'username': uid, 'password': psw, 'service': service},
|
||||
success: function (data) {
|
||||
var html = '<ul><li>Service Id: <code>' + data.registeredService.id + '</code></li>'
|
||||
+ '<li>Service Identifier: <code>' + data.registeredService.serviceId + '</code></li>'
|
||||
+ '<li>Service Name: <code>' + data.registeredService.name + '</code></li>'
|
||||
+ '</ul><p/>';
|
||||
$('#validationresponse').html(html);
|
||||
|
||||
var resp = '<pre>' + JSON.stringify(data.registeredService, null, 4) + '</pre>';
|
||||
$('#serviceJson').html(resp);
|
||||
|
||||
resp = '<pre>' + data.cas1Response + '</pre>';
|
||||
$('#cas1').html(resp);
|
||||
|
||||
resp = '<pre>' + data.cas2Response + '</pre>';
|
||||
$('#cas2').html(resp);
|
||||
|
||||
resp = '<pre>' + data.cas3XmlResponse + '</pre>';
|
||||
$('#cas3Xml').html(resp);
|
||||
|
||||
resp = '<pre>' + data.cas3JsonResponse + '</pre>';
|
||||
$('#cas3Json').html(resp);
|
||||
},
|
||||
error: function (err) {
|
||||
var html = '<div class=\'alert alert-danger\'>'
|
||||
+ '<h4>Response Error</h4>'
|
||||
+ 'Status: <code>' + err.responseJSON.status + '</code><p/>'
|
||||
+ 'Exception: <code>' + err.responseJSON.exception + '</code><p/>'
|
||||
+ 'Message: <code>' + err.responseJSON.message + '</code><p/>'
|
||||
+ '</div>';
|
||||
$('#validationresponse').html(html);
|
||||
},
|
||||
complete: function() {
|
||||
$('#submitRelease').removeAttr('disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
$('#myTabs a').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).tab('show');
|
||||
});
|
||||
|
||||
(function () {
|
||||
var getData = function () {
|
||||
$.getJSON(urls.getEvents, function (data) {
|
||||
authnEventsTable(data);
|
||||
});
|
||||
};
|
||||
|
||||
var authnEventsTable = function (jsonData) {
|
||||
var t = $('#authnEventsTable').DataTable({
|
||||
'order': [[2, 'desc']],
|
||||
retrieve: true,
|
||||
columnDefs: [
|
||||
{
|
||||
'targets': 0,
|
||||
render: function (data) {
|
||||
return '<span class="glyphicon glyphicon-flash" aria-hidden="true"> </span>' + data;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
for (var i = 0; i < jsonData.length; i++) {
|
||||
var rec = jsonData[i];
|
||||
|
||||
var type = rec.type.split('.');
|
||||
t.row.add([
|
||||
type[type.length - 1],
|
||||
rec.principalId,
|
||||
new Date(rec.creationTime*1000),
|
||||
new Date(rec.timestamp),
|
||||
rec.properties.agent,
|
||||
rec.clientIpAddress,
|
||||
rec.serverIpAddress,
|
||||
rec.properties.geoLatitude === 'undefined' ? '' : Number(rec.properties.geoLatitude).toFixed(2),
|
||||
rec.properties.geoLongitude === 'undefined' ? '' : Number(rec.properties.geoLongitude).toFixed(2),
|
||||
rec.properties.geoAccuracy === 'undefined' ? '' : Number(rec.properties.geoAccuracy).toFixed(2)
|
||||
]).draw(false);
|
||||
}
|
||||
};
|
||||
|
||||
// initialization *******
|
||||
(function init () {
|
||||
getData();
|
||||
})();
|
||||
})();
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/* global trackGeoLocation, jqueryReady */
|
||||
|
||||
/* exported resourceLoadedSuccessfully */
|
||||
|
||||
function requestGeoPosition() {
|
||||
// console.log('Requesting GeoLocation data from the browser...');
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(showGeoPosition, logGeoLocationError,
|
||||
{maximumAge: 600000, timeout: 5000, enableHighAccuracy: true});
|
||||
} else {
|
||||
// console.log('Browser does not support Geo Location');
|
||||
}
|
||||
}
|
||||
|
||||
function logGeoLocationError(error) {
|
||||
switch (error.code) {
|
||||
case error.PERMISSION_DENIED:
|
||||
// console.log('User denied the request for GeoLocation.');
|
||||
break;
|
||||
case error.POSITION_UNAVAILABLE:
|
||||
// console.log('Location information is unavailable.');
|
||||
break;
|
||||
case error.TIMEOUT:
|
||||
// console.log('The request to get user location timed out.');
|
||||
break;
|
||||
default:
|
||||
// console.log('An unknown error occurred.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function showGeoPosition(position) {
|
||||
$('[name="geolocation"]').val(position.coords.latitude + ','
|
||||
+ position.coords.longitude + ',' + position.coords.accuracy + ',' + position.timestamp);
|
||||
}
|
||||
|
||||
|
||||
function preserveAnchorTagOnForm() {
|
||||
$('#fm1').submit(function () {
|
||||
var location = self.document.location;
|
||||
var hash = decodeURIComponent(location.hash);
|
||||
|
||||
if (hash != undefined && hash != '' && hash.indexOf('#') === -1) {
|
||||
hash = '#' + hash;
|
||||
}
|
||||
|
||||
var action = $('#fm1').attr('action');
|
||||
if (action == undefined) {
|
||||
action = location.href;
|
||||
} else {
|
||||
var qidx = location.href.indexOf('?');
|
||||
if (qidx != -1) {
|
||||
var queryParams = location.href.substring(qidx);
|
||||
action += queryParams;
|
||||
}
|
||||
}
|
||||
action += hash;
|
||||
$('#fm1').attr('action', action);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function areCookiesEnabled() {
|
||||
if ($.cookie == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.cookie('cookiesEnabled', 'true');
|
||||
var value = $.cookie('cookiesEnabled');
|
||||
$.removeCookie('cookiesEnabled');
|
||||
return value != undefined;
|
||||
|
||||
}
|
||||
|
||||
function disableEmptyInputFormSubmission() {
|
||||
var fields = $('#fm1 input[name="username"],[name="password"]');
|
||||
|
||||
if (fields.length == 2) {
|
||||
fields.on('input', function (event) {
|
||||
var enableSubmission = $('#fm1 input[name="username"]').val().trim() &&
|
||||
$('#fm1 input[name="password"]').val().trim();
|
||||
|
||||
if (enableSubmission) {
|
||||
$('#fm1 input[name=submit]').removeAttr('disabled');
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
$('#fm1 input[name=submit]').attr('disabled', 'true');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle auto-complete events to the extent possible.
|
||||
*/
|
||||
if ($('#fm1 input[name="username"]').length > 0) {
|
||||
setTimeout(function () {
|
||||
var uid = $('#username').val();
|
||||
if (uid != null && uid != '') {
|
||||
$('#username').change();
|
||||
$('#username').focus();
|
||||
$('#fm1 input[name=submit]').removeAttr('disabled');
|
||||
}
|
||||
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
function resourceLoadedSuccessfully() {
|
||||
$(document).ready(function () {
|
||||
|
||||
if (trackGeoLocation) {
|
||||
requestGeoPosition();
|
||||
}
|
||||
|
||||
if ($(':focus').length === 0) {
|
||||
$('input:visible:enabled:first').focus();
|
||||
}
|
||||
|
||||
if (areCookiesEnabled()) {
|
||||
$('#cookiesDisabled').hide();
|
||||
} else {
|
||||
$('#cookiesDisabled').show();
|
||||
}
|
||||
|
||||
disableEmptyInputFormSubmission();
|
||||
preserveAnchorTagOnForm();
|
||||
|
||||
$('#capslock-on').hide();
|
||||
$('#fm1 input[name="username"],[name="password"]').trigger('input');
|
||||
$('#fm1 input[name="username"]').focus();
|
||||
|
||||
$('#password').keypress(function (e) {
|
||||
var s = String.fromCharCode(e.which);
|
||||
if (s.toUpperCase() === s && s.toLowerCase() !== s && !e.shiftKey) {
|
||||
$('#capslock-on').show();
|
||||
} else {
|
||||
$('#capslock-on').hide();
|
||||
}
|
||||
});
|
||||
if (typeof(jqueryReady) == 'function') {
|
||||
jqueryReady();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
var strings = strings;
|
||||
|
||||
/* global data */
|
||||
$(document).ready(function(){
|
||||
resolveAttributes();
|
||||
optionSelected();
|
||||
});
|
||||
|
||||
function optionSelected() {
|
||||
var v = $('input[name=option]:checked', '#fm1').val();
|
||||
if (v == 0) {
|
||||
$('#reminderPanel').hide();
|
||||
$('#reminderTab').hide();
|
||||
} else {
|
||||
$('#reminderPanel').show();
|
||||
$('#reminderTab').show();
|
||||
}
|
||||
}
|
||||
|
||||
function resolveAttributes() {
|
||||
var table;
|
||||
|
||||
if ( $.fn.dataTable.isDataTable( '#attributesTable' ) ) {
|
||||
table = $('#attributesTable').DataTable();
|
||||
}
|
||||
else {
|
||||
table = $('#attributesTable').DataTable( {
|
||||
paging : false,
|
||||
searching : false,
|
||||
language: {
|
||||
info: strings.info
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
table.clear();
|
||||
var attrs = data.attributes;
|
||||
for (var property in attrs) {
|
||||
if (attrs.hasOwnProperty(property)) {
|
||||
table.row.add([
|
||||
'<code>' + property + '</code>', '<code>' + attrs[property] + '</code>'
|
||||
]).draw(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
var infoEl = $('tr.info').clone();
|
||||
var strings = strings;
|
||||
|
||||
/* Formatting function for row details - modify as you need */
|
||||
function format(d) {
|
||||
var detail = infoEl.clone();
|
||||
// show
|
||||
$(detail).toggleClass('hidden');
|
||||
// add data
|
||||
var dec = d.decision;
|
||||
// date
|
||||
detail.find('.created-date')[0].append(date(dec.createdDate).toLocaleString());
|
||||
// options & reminder
|
||||
if (dec.options === 'ALWAYS') {
|
||||
detail.find('.consent-reminder').parent().remove();
|
||||
} else {
|
||||
var unit = dec.reminderTimeUnit.toLowerCase();
|
||||
detail.find('.consent-reminder span:not(.' + unit + ')').remove();
|
||||
if (dec.reminder === 1) {
|
||||
var _unit = detail.find('.consent-reminder span.' + unit);
|
||||
_unit.html(_unit.text().slice(0, -1));
|
||||
}
|
||||
detail.find('.consent-reminder').prepend(dec.reminder);
|
||||
}
|
||||
detail.find('.consent-options span:not(.' + dec.options.toLowerCase().replace('_','-') + ')').remove();
|
||||
// render attribute table
|
||||
attributeTable(detail.find('.consent-attributes'),d.attributes);
|
||||
// enable tooltip
|
||||
detail.find('.consent-options [data-toggle="tooltip"]').tooltip();
|
||||
// setup delete button
|
||||
var del = detail.find('.btn-danger');
|
||||
var data = { 'id': dec.id, 'service': dec.service };
|
||||
del.on('click', data, function (e) {
|
||||
e.preventDefault();
|
||||
confirm(e.data.id, e.data.service);
|
||||
});
|
||||
|
||||
return detail;
|
||||
}
|
||||
|
||||
function alertUser(message, alertType) {
|
||||
$('#alertWrapper').append('<div id="alertdiv" class="alert alert-' + alertType + ' alert-dismissible">' +
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' +
|
||||
'<span class="alertMessage">' + message + '</span></div>'
|
||||
);
|
||||
|
||||
setTimeout(function () { // this will automatically close the alert and remove this if the users doesnt close it in 5 secs
|
||||
$('#alertdiv').remove();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function attributeTable(t, attributes) {
|
||||
|
||||
var table;
|
||||
if ( $.fn.dataTable.isDataTable( t ) ) {
|
||||
table = $(t).DataTable();
|
||||
}
|
||||
else {
|
||||
table = $(t).DataTable( {
|
||||
paging : false,
|
||||
searching : false,
|
||||
info: false
|
||||
} );
|
||||
}
|
||||
|
||||
table.clear();
|
||||
for (var property in attributes) {
|
||||
if (attributes.hasOwnProperty(property)) {
|
||||
table.row.add([
|
||||
'<code>' + property + '</code>', '<code>' + attributes[property] + '</code>'
|
||||
]).draw(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function date(d) {
|
||||
var date = new Date(d[0],d[1]-1,d[2],d[3],d[4],d[5]);
|
||||
return date;
|
||||
}
|
||||
|
||||
function confirm(decisionId, service) {
|
||||
$('#confirmdiv').remove();
|
||||
var svcStr = service.length > 70 ? service.substr(0,68) + '...' : service;
|
||||
var message = strings.confirm.replace('{}', svcStr);
|
||||
$('#alertWrapper').append('<div id="confirmdiv" class="alert alert-warning">' +
|
||||
'<span class="alertMessage">' + message + '</span><br/>' +
|
||||
'<button type="button" id="delete" class="btn btn-xs btn-danger" aria-label="Yes"><strong>' +
|
||||
strings.yes + ' </strong></button>' +
|
||||
'<button type="button" class="btn btn-xs btn-default" aria-label="No" value="' + decisionId + '"><strong>' +
|
||||
strings.no + '</strong></button></div>'
|
||||
);
|
||||
$('#confirmdiv .btn').click(function() {
|
||||
$('#confirmdiv').alert('close');
|
||||
});
|
||||
$('#delete').click(function() {
|
||||
removeDecision(decisionId);
|
||||
});
|
||||
}
|
||||
|
||||
function removeDecision(decisionId) {
|
||||
var factory = {};
|
||||
factory.httpHeaders = {};
|
||||
factory.httpHeaders[$('meta[name=\'_csrf_header\']').attr('content')] = $('meta[name=\'_csrf\']').attr('content');
|
||||
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
url: urls.delete,
|
||||
data: {decisionId: decisionId},
|
||||
headers: factory.httpHeaders,
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
// Reinitialize the table data
|
||||
$('#consentDecisions').DataTable().ajax.reload();
|
||||
|
||||
if (!data) {
|
||||
alertUser(strings.error, 'danger');
|
||||
} else {
|
||||
alertUser(strings.success, 'success');
|
||||
// Reload the page
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alertUser('There appears to be an error. Please try your request again.', 'danger');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var consentDecisions = (function () {
|
||||
var createDataTable = function () {
|
||||
$('#consentDecisions').DataTable({
|
||||
'order': [[0, 'desc']],
|
||||
'initComplete': function (settings, json) {
|
||||
if (!json || json.length == 0) {
|
||||
$('#consent-decisons').hide();
|
||||
$('#loadingMessage').hide();
|
||||
$('#no-consent-decisions').show();
|
||||
} else {
|
||||
$('#loadingMessage').hide();
|
||||
$('#no-consent-decisions').hide();
|
||||
$('#consent-decisons').show();
|
||||
}
|
||||
},
|
||||
'language': strings.data,
|
||||
'paging': false,
|
||||
'ajax': {
|
||||
'url': urls.getConsentDecisions,
|
||||
'dataSrc': ''
|
||||
},
|
||||
'data': consentDecisions,
|
||||
'columnDefs': [
|
||||
{
|
||||
'targets': 0,
|
||||
'className': 'created-date',
|
||||
'data': function (row) {
|
||||
return date(row.decision.createdDate);
|
||||
},
|
||||
'render': function (data) {
|
||||
var opts = { year: 'numeric', month: 'numeric' };
|
||||
return '<div class="label label-primary"><span class="hidden">' + data.toISOString() +
|
||||
'</span>' + data.toLocaleDateString('en', opts ) +
|
||||
'</div>';
|
||||
}
|
||||
},
|
||||
{
|
||||
'targets': 1,
|
||||
'data': 'decision.service',
|
||||
'className': 'col service-id',
|
||||
'render': function (data) {
|
||||
if ($(window).width() <= 855) {
|
||||
return data.length > 70 ?
|
||||
'<span title="' + data + '">' + data.substr(0, 68) + '...</span>' : data;
|
||||
} else {
|
||||
return data.length > 180 ?
|
||||
'<span title="' + data + '">' + data.substr(0, 178) + '...</span>' : data;
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
var addEventHandlers = function () {
|
||||
|
||||
/* Performs logout for consent application, no SLO */
|
||||
$('#logout').click(function() {
|
||||
var logout = window.location + '/logout';
|
||||
window.location.assign(logout);
|
||||
});
|
||||
|
||||
// Add event listener for opening and closing details
|
||||
$(document).on('click', '#consentDecisions > tbody > tr:not(.info)', function () {
|
||||
var table = $('#consentDecisions').DataTable();
|
||||
var tr = $(this);
|
||||
var row = table.row(tr);
|
||||
|
||||
if (row.child.isShown()) {
|
||||
// This row is already open - close it
|
||||
row.child.hide();
|
||||
tr.removeClass('shown');
|
||||
}
|
||||
else {
|
||||
// Open this row
|
||||
row.child(format(row.data()), 'info').show();
|
||||
tr.addClass('shown');
|
||||
}
|
||||
});
|
||||
};
|
||||
// initialization *******
|
||||
(function init() {
|
||||
createDataTable();
|
||||
addEventHandlers();
|
||||
})();
|
||||
|
||||
// Public Methods
|
||||
return {
|
||||
/**
|
||||
* Not used
|
||||
*/
|
||||
};
|
||||
})();
|
||||
+1
@@ -0,0 +1 @@
|
||||
(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{var o=t();o._onReady(o.init);e.Duo=o}})(this,function(){var e=/^(?:AUTH|ENROLL)+\|[A-Za-z0-9\+\/=]+\|[A-Za-z0-9\+\/=]+$/;var t=/^ERR\|[\w\s\.\(\)]+$/;var o=/^DUO_OPEN_WINDOW\|/;var n=["duo.com","duosecurity.com","duomobile.s3-us-west-1.amazonaws.com"];var i="duo_iframe",a="",r="sig_response",s,u,f,d,m,c;function l(e,t){throw new Error("Duo Web SDK error: "+e+(t?"\n"+"See "+t+" for more information":""))}function h(e){return e.replace(/([a-z])([A-Z])/,"$1-$2").toLowerCase()}function p(e,t){if("dataset"in e){return e.dataset[t]}else{return e.getAttribute("data-"+h(t))}}function g(e,t,o,n){if("addEventListener"in window){e.addEventListener(t,n,false)}else{e.attachEvent(o,n)}}function w(e,t,o,n){if("removeEventListener"in window){e.removeEventListener(t,n,false)}else{e.detachEvent(o,n)}}function v(e){g(document,"DOMContentLoaded","onreadystatechange",e)}function _(e){w(document,"DOMContentLoaded","onreadystatechange",e)}function b(e){g(window,"message","onmessage",e)}function E(e){w(window,"message","onmessage",e)}function y(e){if(!e){return}if(e.indexOf("ERR|")===0){l(e.split("|")[1])}if(e.indexOf(":")===-1||e.split(":").length!==2){l("Duo was given a bad token. This might indicate a configuration "+"problem with one of Duo's client libraries.","https://www.duosecurity.com/docs/duoweb#first-steps")}var t=e.split(":");u=e;f=t[0];d=t[1];return{sigRequest:e,duoSig:t[0],appSig:t[1]}}function D(){m=document.getElementById(i);if(!m){throw new Error("This page does not contain an iframe for Duo to use."+'Add an element like <iframe id="duo_iframe"></iframe> '+"to this page. "+"See https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe "+"for more information.")}q();_(D)}function O(n){return Boolean(n.origin==="https://"+s&&typeof n.data==="string"&&(n.data.match(e)||n.data.match(t)||n.data.match(o)))}function R(e){if(e){if(e.host){s=e.host}if(e.sig_request){y(e.sig_request)}if(e.post_action){a=e.post_action}if(e.post_argument){r=e.post_argument}if(e.iframe){if(e.iframe.tagName){m=e.iframe}else if(typeof e.iframe==="string"){i=e.iframe}}if(typeof e.submit_callback==="function"){c=e.submit_callback}}if(m){q()}else{m=document.getElementById(i);if(m){q()}else{v(D)}}_(R)}function A(e){if(O(e)){if(e.data.match(o)){var t=e.data.substring("DUO_OPEN_WINDOW|".length);if(L(t)){window.open(t,"_self")}}else{B(e.data);E(A)}}}function L(e){if(!e){return false}var t=document.createElement("a");t.href=e;if(t.protocol==="duotrustedendpoints:"){return true}else if(t.protocol!=="https:"){return false}for(var o=0;o<n.length;o++){if(t.hostname.endsWith("."+n[o])||t.hostname===n[o]){return true}}return false}function q(){if(!s){s=p(m,"host");if(!s){l("No API hostname is given for Duo to use. Be sure to pass "+"a `host` parameter to Duo.init, or through the `data-host` "+"attribute on the iframe element.","https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe")}}if(!f||!d){y(p(m,"sigRequest"));if(!f||!d){l("No valid signed request is given. Be sure to give the "+"`sig_request` parameter to Duo.init, or use the "+"`data-sig-request` attribute on the iframe element.","https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe")}}if(a===""){a=p(m,"postAction")||a}if(r==="sig_response"){r=p(m,"postArgument")||r}m.src=["https://",s,"/frame/web/v1/auth?tx=",f,"&parent=",encodeURIComponent(document.location.href),"&v=2.6"].join("");b(A)}function B(e){var t=document.createElement("input");t.type="hidden";t.name=r;t.value=e+":"+d;var o=document.getElementById("duo_form");if(!o){o=document.createElement("form");m.parentElement.insertBefore(o,m.nextSibling)}o.method="POST";o.action=a;o.appendChild(t);if(typeof c==="function"){c.call(null,o)}else{o.submit()}}return{init:R,_onReady:v,_parseSigRequest:y,_isDuoMessage:O,_doPostBack:B}});
|
||||
+342
@@ -0,0 +1,342 @@
|
||||
/* global logConfigFileLocation, SockJS, Stomp */
|
||||
var stompClient = null;
|
||||
|
||||
function setConnected(connected) {
|
||||
|
||||
var el = document.getElementById('websocketStatus');
|
||||
el.style.visibility = connected ? 'visible' : 'hidden';
|
||||
el.class = connected ? 'alert alert-info' : 'alert alert-danger';
|
||||
|
||||
if (!connected) {
|
||||
el.innerHTML = 'Disconnected!';
|
||||
} else {
|
||||
el.innerHTML = 'Connected to CAS. Streaming and tailing logs based on <kbd>[' + logConfigFileLocation + ']</kbd>...';
|
||||
}
|
||||
}
|
||||
|
||||
function connect() {
|
||||
$('#logoutputarea').empty();
|
||||
var socket = new SockJS(urls.reportsWebsocket);
|
||||
stompClient = Stomp.over(socket);
|
||||
stompClient.connect({}, function () {
|
||||
setConnected(true);
|
||||
stompClient.subscribe('/topic/logs', function (msg) {
|
||||
if (msg != null && msg.body != '') {
|
||||
showLogs(msg.body);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
$('#logoutputarea').empty();
|
||||
$('#logoutputarea').attr('readonly', 'readonly');
|
||||
|
||||
if (stompClient != null) {
|
||||
stompClient.disconnect();
|
||||
}
|
||||
setConnected(false);
|
||||
}
|
||||
|
||||
function showLogs(message) {
|
||||
if (message != '') {
|
||||
$('#logoutputarea').val($('#logoutputarea').val() + '\n' + message);
|
||||
$('#logoutputarea').scrollTop(document.getElementById('logoutputarea').scrollHeight);
|
||||
}
|
||||
}
|
||||
|
||||
disconnect();
|
||||
connect();
|
||||
setInterval(function () {
|
||||
}, 100);
|
||||
|
||||
/*************
|
||||
*
|
||||
***************/
|
||||
$('#myTabs a').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).tab('show');
|
||||
});
|
||||
|
||||
var alertHandler = (function () {
|
||||
var alertContainer = $('#alert-container');
|
||||
var create = function (message, state) {
|
||||
//console.log('create the alert');
|
||||
alertContainer.html('<div class="alert alert-' + state + ' alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button><span>' + message + '</span></div>');
|
||||
|
||||
alertContainer.delay(2000).fadeOut('slow');
|
||||
};
|
||||
|
||||
var destroy = function () {
|
||||
alertContainer.empty();
|
||||
};
|
||||
|
||||
return {
|
||||
dismiss: function () {
|
||||
destroy();
|
||||
},
|
||||
show: function (msg, state) {
|
||||
create(msg, state);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
var loggingDashboard = (function () {
|
||||
var json = null;
|
||||
|
||||
var logLevels = ['trace', 'debug', 'info', 'warn', 'error'];
|
||||
|
||||
var getData = function () {
|
||||
$.getJSON(urls.getConfiguration, function (data) {
|
||||
json = data;
|
||||
loggerTable();
|
||||
});
|
||||
};
|
||||
|
||||
var getAuditData = function () {
|
||||
$.getJSON(urls.getAuditLog, function (data) {
|
||||
if ($(data).length > 0) {
|
||||
loggerTableAudit(data);
|
||||
} else {
|
||||
$('#auditLogTable').DataTable();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var loggerTableAudit = function (jsonData) {
|
||||
var t = $('#auditLogTable').DataTable({
|
||||
'autoWidth': false,
|
||||
'order': [[3, 'desc']],
|
||||
retrieve: true,
|
||||
columnDefs: [
|
||||
|
||||
{'width': '5%', 'targets': 0},
|
||||
{'width': '100%', 'targets': 1},
|
||||
{
|
||||
'targets': 2,
|
||||
render: function (data) {
|
||||
var dd = data.toLowerCase();
|
||||
if (dd.indexOf('created') != -1) {
|
||||
return '<span class="glyphicon glyphicon-plus" aria-hidden="true"> </span>' + data;
|
||||
}
|
||||
if (dd.indexOf('validated') != -1) {
|
||||
return '<span class="glyphicon glyphicon-ok" aria-hidden="true"> </span>' + data;
|
||||
}
|
||||
if (dd.indexOf('destroyed') != -1 || dd.indexOf('deleted') != -1) {
|
||||
return '<span class="glyphicon glyphicon-minus" aria-hidden="true"> </span>' + data;
|
||||
}
|
||||
|
||||
if (dd.indexOf('success') != -1) {
|
||||
return '<span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"> </span>' + data;
|
||||
}
|
||||
if (dd.indexOf('failed') != -1) {
|
||||
return '<span class="glyphicon glyphicon-thumbs-down" aria-hidden="true"> </span>' + data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
for (var i = 0; i < jsonData.length; i++) {
|
||||
var rec = jsonData[i];
|
||||
t.row.add([
|
||||
rec.principal,
|
||||
rec.resourceOperatedUpon,
|
||||
rec.actionPerformed,
|
||||
new Date(rec.whenActionWasPerformed),
|
||||
rec.clientIpAddress,
|
||||
rec.serverIpAddress
|
||||
]).draw(false);
|
||||
}
|
||||
};
|
||||
|
||||
var loggerTable = function () {
|
||||
$('#loggersTable').DataTable({
|
||||
'autoWidth': false,
|
||||
'order': [[1, 'desc']],
|
||||
data: json.loggers,
|
||||
'drawCallback': function () {
|
||||
var api = this.api();
|
||||
|
||||
if (api.page.info().pages > 1) {
|
||||
$('#' + $.fn.dataTable.tables()[0].id + '_paginate')[0].style.display = 'block';
|
||||
} else {
|
||||
$('#' + $.fn.dataTable.tables()[0].id + '_paginate')[0].style.display = 'none';
|
||||
}
|
||||
},
|
||||
'initComplete': function (settings) {
|
||||
if (!settings.aoData || settings.aoData.length == 0) {
|
||||
$('#loadingMessage').addClass('d-none');
|
||||
$('#errorLoadingData').removeClass('d-none');
|
||||
} else {
|
||||
$('#loadingMessage').addClass('d-none');
|
||||
$('#errorLoadingData').addClass('d-none');
|
||||
$('#loggingDashboard .tabsContainer').removeClass('d-none');
|
||||
}
|
||||
},
|
||||
'processing': true,
|
||||
columnDefs: [
|
||||
{
|
||||
'targets': 0,
|
||||
'className': 'details-control',
|
||||
'orderable': false,
|
||||
'data': 'appenders',
|
||||
'defaultContent': '',
|
||||
render: function (data) {
|
||||
if (data.length > 0) {
|
||||
return '<span></span>';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 1,
|
||||
data: 'name',
|
||||
className: 'col-xs-5'
|
||||
},
|
||||
{
|
||||
targets: 2,
|
||||
data: 'additive',
|
||||
className: 'additive col-xs-2',
|
||||
render: function (data) {
|
||||
if (data) {
|
||||
return '<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>';
|
||||
} else {
|
||||
return '<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>';
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 3,
|
||||
data: 'state',
|
||||
className: 'col-xs-2'
|
||||
},
|
||||
{
|
||||
targets: 4,
|
||||
data: 'level',
|
||||
className: 'col-xs-3',
|
||||
render: function (data, type, full, meta) {
|
||||
return toggleSwitch(data, type, full, meta);
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
var toggleSwitch = function (data, type, full) {
|
||||
// Todo: Add additional colors for the other options
|
||||
//console.log('toggleSwitch data',data);
|
||||
//console.log('type',type);
|
||||
//console.log('full',full);
|
||||
//console.log('meta',meta);
|
||||
//console.log(logLevels);
|
||||
var btnColor;
|
||||
|
||||
switch (data.toLowerCase()) {
|
||||
case 'error':
|
||||
btnColor = 'danger';
|
||||
break;
|
||||
case 'info':
|
||||
btnColor = 'info';
|
||||
break;
|
||||
case 'warn':
|
||||
btnColor = 'warning';
|
||||
break;
|
||||
default:
|
||||
btnColor = 'default';
|
||||
}
|
||||
var btnGroup = '<div class="dropdown" data-logger="' + full + '"><button class="btn btn-sm btn-block bg-' + btnColor + ' dropdown-toggle" name="recordinput" data-toggle="dropdown">' + data + ' <span class="caret"></span></button>' +
|
||||
'<div class="dropdown-menu">';
|
||||
for (var i = 0; i < logLevels.length; i++) {
|
||||
btnGroup += '<a class="dropdown-item" href="#">' + logLevels[i].toUpperCase() + '</a>';
|
||||
}
|
||||
btnGroup += '</div>';
|
||||
|
||||
return btnGroup;
|
||||
};
|
||||
|
||||
/* Formatting function for row details - modify as you need */
|
||||
var viewAppenders = function (data) {
|
||||
return '<table class="table table-bordered row-detail"><tbody><tr class="">' +
|
||||
'<td class="field-label active">Appenders:</td>' +
|
||||
'<td><kbd>' + JSON.stringify(data.appenders, null, 2) + '</kbd></td>' +
|
||||
'</tr>' +
|
||||
'</tbody></table>';
|
||||
};
|
||||
|
||||
var addEventHandlers = function () {
|
||||
//console.log('addEventHAndlers()');
|
||||
|
||||
$(document).on('click', '#loggersTable .dropdown-menu a', function (e) {
|
||||
//console.log('status change', this);
|
||||
e.preventDefault();
|
||||
var selText = $(this).text();
|
||||
|
||||
changeLogLevel(selText, this);
|
||||
});
|
||||
|
||||
$(document).on('click', '#loggersTable tbody td.details-control span', function () {
|
||||
var table = $('#loggersTable').DataTable();
|
||||
var tr = $(this).closest('tr');
|
||||
var row = table.row(tr);
|
||||
|
||||
if (row.child.isShown()) {
|
||||
// This row is already open - close it
|
||||
row.child.hide();
|
||||
tr.removeClass('shown');
|
||||
} else {
|
||||
// Open this row
|
||||
row.child(viewAppenders(row.data()), 'info').show();
|
||||
tr.addClass('shown');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var changeLogLevel = function (newLevel, el) {
|
||||
/**
|
||||
* POST - /cas/status/logging/updateLoggerLevel
|
||||
* Allows you to change the log level for given LOGGER. Parameters are:
|
||||
* loggerName, loggerLevel, additive (true/false)
|
||||
*/
|
||||
var table = $('#loggersTable').DataTable();
|
||||
var data = table.row($(el).closest('tr')[0]).data();
|
||||
|
||||
if (newLevel != data.level) {
|
||||
var cell = table.cell($(el).closest('td')[0]);
|
||||
|
||||
$.post(urls.updateLevel, {
|
||||
loggerName: data.name,
|
||||
loggerLevel: newLevel,
|
||||
additive: data.additive
|
||||
}, function () {
|
||||
cell.data(newLevel).draw();
|
||||
alertHandler.show('Successfully changed.', 'success');
|
||||
}).fail(function () {
|
||||
alertHandler.show('Error saving change. Please try again', 'danger');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// initialization *******
|
||||
(function init() {
|
||||
})();
|
||||
|
||||
return {
|
||||
init: function () {
|
||||
getData();
|
||||
addEventHandlers();
|
||||
getAuditData();
|
||||
},
|
||||
getJson: function () {
|
||||
return json;
|
||||
},
|
||||
showLoggersTable: function () {
|
||||
loggerTable();
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
loggingDashboard.init();
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/* global jqueryReady, policyPattern, zxcvbn, passwordStrengthI18n */
|
||||
/*eslint-disable no-unused-vars*/
|
||||
function jqueryReady() {
|
||||
var strength = passwordStrengthI18n;
|
||||
|
||||
$.fn.zxcvbnProgressBar = function (options) {
|
||||
|
||||
//init settings
|
||||
var settings = $.extend({
|
||||
allProgressBarClasses: 'progress-bar-danger progress-bar-warning progress-bar-success progress-bar-striped active',
|
||||
progressBarClass0: 'progress-bar-danger progress-bar-striped active',
|
||||
progressBarClass1: 'progress-bar-danger progress-bar-striped active',
|
||||
progressBarClass2: 'progress-bar-warning progress-bar-striped active',
|
||||
progressBarClass3: 'progress-bar-success',
|
||||
progressBarClass4: 'progress-bar-success'
|
||||
}, options);
|
||||
|
||||
return this.each(function () {
|
||||
settings.progressBar = this;
|
||||
//init progress bar display
|
||||
UpdateProgressBar();
|
||||
//Update progress bar on each keypress of password input
|
||||
$(settings.passwordInput).keyup(function (event) {
|
||||
UpdateProgressBar();
|
||||
});
|
||||
});
|
||||
|
||||
function UpdateProgressBar() {
|
||||
var progressBar = settings.progressBar;
|
||||
var password = $('#password').val();
|
||||
if (password) {
|
||||
var result = zxcvbn(password, settings.userInputs);
|
||||
//result.score: 0, 1, 2, 3 or 4 - if crack time is less than 10**2, 10**4, 10**6, 10**8, Infinity.
|
||||
var scorePercentage = (result.score + 1) * 20;
|
||||
$(progressBar).css('width', scorePercentage + '%');
|
||||
|
||||
if (result.score == 0) {
|
||||
//weak
|
||||
$(progressBar).removeClass(settings.allProgressBarClasses).addClass(settings.progressBarClass0);
|
||||
$(progressBar).html(strength[0]);
|
||||
}
|
||||
else if (result.score == 1) {
|
||||
//normal
|
||||
$(progressBar).removeClass(settings.allProgressBarClasses).addClass(settings.progressBarClass1);
|
||||
$(progressBar).html(strength[1]);
|
||||
}
|
||||
else if (result.score == 2) {
|
||||
//medium
|
||||
$(progressBar).removeClass(settings.allProgressBarClasses).addClass(settings.progressBarClass2);
|
||||
$(progressBar).html(strength[2]);
|
||||
}
|
||||
else if (result.score == 3) {
|
||||
//strong
|
||||
$(progressBar).removeClass(settings.allProgressBarClasses).addClass(settings.progressBarClass3);
|
||||
$(progressBar).html(strength[3]);
|
||||
}
|
||||
else if (result.score == 4) {
|
||||
//very strong
|
||||
$(progressBar).removeClass(settings.allProgressBarClasses).addClass(settings.progressBarClass4);
|
||||
$(progressBar).html(strength[4]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$(progressBar).css('width', '0%');
|
||||
$(progressBar).removeClass(settings.allProgressBarClasses).addClass(settings.progressBarClass0);
|
||||
$(progressBar).html('');
|
||||
}
|
||||
}
|
||||
};
|
||||
var policyPatternRegex = new RegExp(policyPattern);
|
||||
var password = document.getElementById('password');
|
||||
var confirmed = document.getElementById('confirmedPassword');
|
||||
|
||||
|
||||
password.addEventListener('input', validate);
|
||||
confirmed.addEventListener('input', validate);
|
||||
|
||||
var alertSettings = {
|
||||
allAlertClasses: 'fa-times-circle fa-exclamation-circle fa-info-circle fa-check-circle',
|
||||
alertClassDanger: 'fa-times-circle',
|
||||
alertClassWarning: 'fa-exclamation-circle',
|
||||
alertClassInfo: 'fa-info-circle',
|
||||
alertClassSuccess: 'fa-check-circle'
|
||||
};
|
||||
|
||||
function validate() {
|
||||
var val = password.value;
|
||||
var cnf = confirmed.value;
|
||||
|
||||
$('#password-policy-violation-msg').hide();
|
||||
$('#password-confirm-mismatch-msg').hide();
|
||||
|
||||
var passwordPolicyViolated = val === '' || !policyPatternRegex.test(val);
|
||||
var passwordMismatch = val !== '' && val !== cnf;
|
||||
var disableSubmit = passwordPolicyViolated || passwordMismatch;
|
||||
$('#submit').prop('disabled', disableSubmit);
|
||||
|
||||
var result = zxcvbn(val);
|
||||
$('#strengthProgressBar').zxcvbnProgressBar({ passwordInput: '#password' });
|
||||
|
||||
// Check strength, update the text indicator
|
||||
if (val !== '') {
|
||||
$('#password-strength-warning').text(result.feedback.warning);
|
||||
$('#password-strength-suggestions').text(result.feedback.suggestions);
|
||||
|
||||
var clz = alertSettings.alertClassDanger;
|
||||
switch (result.score) {
|
||||
case 0:
|
||||
case 1:
|
||||
clz = alertSettings.alertClassDanger;
|
||||
break;
|
||||
case 2:
|
||||
clz = alertSettings.alertClassWarning;
|
||||
break;
|
||||
case 3:
|
||||
clz = alertSettings.alertClassInfo;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
default:
|
||||
clz = alertSettings.alertClassSuccess;
|
||||
break;
|
||||
}
|
||||
$('#password-strength-icon').removeClass(alertSettings.allAlertClasses).addClass(clz);
|
||||
} else {
|
||||
$('#password-strength-icon').removeClass(alertSettings.allAlertClasses);
|
||||
$('#password-strength-warning').text('');
|
||||
$('#password-strength-suggestions').text('');
|
||||
}
|
||||
|
||||
// Check for mismatch
|
||||
if (passwordMismatch && cnf !== '') {
|
||||
$('#password-confirm-mismatch-msg').show();
|
||||
}
|
||||
|
||||
// Check password policy
|
||||
if (passwordPolicyViolated) {
|
||||
$('#password-policy-violation-msg').show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2378
File diff suppressed because it is too large
Load Diff
+351
@@ -0,0 +1,351 @@
|
||||
/*eslint-disable no-unused-vars*/
|
||||
String.prototype.padLeft = function (length, character) {
|
||||
return new Array(length - this.length + 1).join(character || ' ') + this;
|
||||
};
|
||||
|
||||
Date.prototype.toFormattedString = function () {
|
||||
return [String(this.getMonth() + 1).padLeft(2, '0'),
|
||||
String(this.getDate()).padLeft(2, '0'),
|
||||
String(this.getFullYear()).substr(2, 2)].join('/') + ' ' +
|
||||
[String(this.getHours()).padLeft(2, '0'),
|
||||
String(this.getMinutes()).padLeft(2, '0')].join(':');
|
||||
};
|
||||
|
||||
function principalAttributes(obj) {
|
||||
var output = '<table class="table table-condensed principal_attributes"><tbody>';
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
if (Array.isArray(obj[key])) {
|
||||
output = output.concat('<tr><td class="field-label active">' + key + '</td><td>' + obj[key].toString() + '</td></tr>');
|
||||
} else {
|
||||
output = output.concat('<tr><td class="field-label active">' + key + '</td><td>' + obj[key] + '</td></tr>');
|
||||
}
|
||||
}
|
||||
}
|
||||
output = output.concat('</tbody></table>');
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function authenticatedServices(obj) {
|
||||
var output = '';
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
output = output.concat('<h5>' + key + '</h5><table class="table table-condensed principal_attributes"><tbody>');
|
||||
for (var foo in obj[key]) {
|
||||
if (obj[key].hasOwnProperty(foo)) {
|
||||
if (Array.isArray(obj[key][foo])) {
|
||||
output = output.concat('<tr><td class="field-label active">' + foo + ':</td><td>' + obj[key][foo].toString() + '</td></tr>');
|
||||
} else {
|
||||
output = output.concat('<tr><td class="field-label active">' + foo + ':</td><td>' + obj[key][foo] + '</td></tr>');
|
||||
}
|
||||
}
|
||||
}
|
||||
output = output.concat('</tbody></table>');
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/* Formatting function for row details - modify as you need */
|
||||
function format(d) {
|
||||
return '<table class="table table-bordered row-detail">' +
|
||||
'<tbody>' +
|
||||
'<tr class="hidden-md hidden-lg">' +
|
||||
'<td class="field-label active">Access Date:</td>' +
|
||||
'<td>' + d.authentication_date_formatted + '</td>' +
|
||||
'</tr>' +
|
||||
'<tr class="hidden-md hidden-lg">' +
|
||||
'<td class="field-label active">Usage Count:</td>' +
|
||||
'<td>' + d.number_of_uses + '</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="field-label active">Ticket Granting Ticket:</td>' +
|
||||
'<td>' + d.ticket_granting_ticket + '</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="field-label active">Principal Attributes:</td>' +
|
||||
'<td>' +
|
||||
principalAttributes(d.principal_attributes) +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="field-label active">Authenticated Services:</td>' +
|
||||
'<td>' +
|
||||
authenticatedServices(d.authenticated_services) +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="field-label active">Ticket Granting Service:</td>' +
|
||||
'<td></td>' +
|
||||
'</tr>' +
|
||||
'</tbody></table>';
|
||||
|
||||
}
|
||||
|
||||
function updateAdminPanels(data) {
|
||||
//$('#totalUsers').text(data.totalPrincipals);
|
||||
$('#totalUsers').text(data.activeSsoSessions.length);
|
||||
$('#totalUsageSessions').text(sum(data.activeSsoSessions, 'number_of_uses'));
|
||||
//$('#totalProxied').text(data.totalTicketGrantingTickets);
|
||||
$('#totalTGTs').text(data.totalTicketGrantingTickets);
|
||||
//$('#totalTGTs').text( sum(data.activeSsoSessions, 'is_proxied' ) );
|
||||
}
|
||||
|
||||
function sum(obj, prop) {
|
||||
var sum = 0;
|
||||
for (var el in obj) {
|
||||
if (obj.hasOwnProperty(el)) {
|
||||
sum += ( typeof obj[el][prop] == 'boolean' ) ? +obj[el][prop] : obj[el][prop];
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/*
|
||||
function showError(msg) {
|
||||
$('#msg').removeClass();
|
||||
$('#msg').addClass('errors');
|
||||
$('#msg').text(msg);
|
||||
$('#msg').show();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
function showInfo(msg) {
|
||||
$('#msg').removeClass();
|
||||
$('#msg').addClass('info');
|
||||
$('#msg').text(msg);
|
||||
$('#msg').show();
|
||||
}
|
||||
*/
|
||||
|
||||
function alertUser(message, alertType) {
|
||||
$('#alertWrapper').append('<div id="alertdiv" class="alert alert-' + alertType + ' alert-dismissible">' +
|
||||
'<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' +
|
||||
'<span class="alertMessage">' + message + '</span></div>'
|
||||
);
|
||||
|
||||
setTimeout(function () { // this will automatically close the alert and remove this if the users doesnt close it in 5 secs
|
||||
$('#alertdiv').remove();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function removeSession(ticketId) {
|
||||
var factory = {};
|
||||
factory.httpHeaders = {};
|
||||
factory.messages = {};
|
||||
factory.httpHeaders[$('meta[name=\'_csrf_header\']').attr('content')] = $('meta[name=\'_csrf\']').attr('content');
|
||||
|
||||
factory.ticketId = ticketId;
|
||||
|
||||
|
||||
if (ticketId && (ticketId == 'ALL' || ticketId == 'PROXIED' || ticketId == 'DIRECT' )) {
|
||||
factory.url = urls.destroy.all;
|
||||
factory.data = {type: ticketId};
|
||||
factory.messages.success = 'Removed <strong>' + ticketId + '</strong> tickets successfully.';
|
||||
factory.messages.error = 'Could not remove <strong>' + ticketId + '</strong> tickets.';
|
||||
} else {
|
||||
factory.url = urls.destroy.single;
|
||||
factory.data = {ticketGrantingTicket: factory.ticketId};
|
||||
factory.messages.success = 'Ticket is removed successfully.';
|
||||
factory.messages.error = 'Ticket is not removed successfully.';
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
url: factory.url,
|
||||
//data: { ticketGrantingTicket: factory.ticketId, type: 'ALL' },
|
||||
data: factory.data,
|
||||
headers: factory.httpHeaders,
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
// Reinitialize the table data
|
||||
$('#ssoSessions').DataTable().ajax.reload();
|
||||
|
||||
if (data.status != 200) {
|
||||
alertUser(factory.messages.error, 'danger');
|
||||
} else {
|
||||
alertUser(factory.messages.success, 'success');
|
||||
// Reload the page
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alertUser('There appears to be an error. Please try your request again.', 'danger');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var ssoSessions = (function () {
|
||||
var createDataTable = function () {
|
||||
$('#ssoSessions').DataTable({
|
||||
'order': [[3, 'desc']],
|
||||
'initComplete': function (settings, json) {
|
||||
if (!json || json.activeSsoSessions.length == 0) {
|
||||
$('#loadingMessage').hide();
|
||||
$('#no-cas-sessions').show();
|
||||
} else {
|
||||
updateAdminPanels(json);
|
||||
|
||||
$('#loadingMessage').hide();
|
||||
$('#no-cas-sessions').hide();
|
||||
$('#cas-sessions').show();
|
||||
}
|
||||
},
|
||||
'language': {
|
||||
//"infoEmpty": "No active sessions were found",
|
||||
'emptyTable': 'No sessions found',
|
||||
'zeroRecords': 'No matching sessions found'
|
||||
},
|
||||
'processing': true,
|
||||
'ajax': {
|
||||
'url': urls.getSessions,
|
||||
'dataSrc': 'activeSsoSessions'
|
||||
},
|
||||
|
||||
columnDefs: [
|
||||
{
|
||||
'targets': 0,
|
||||
'className': 'details-control',
|
||||
'orderable': false,
|
||||
'data': null,
|
||||
'defaultContent': ''
|
||||
},
|
||||
{
|
||||
'targets': 1,
|
||||
'data': 'is_proxied',
|
||||
'className': 'col-xs-2 col-md-1',
|
||||
'render': function (data) {
|
||||
if (data === true) {
|
||||
return '<span class="label label-primary">Proxy</span>';
|
||||
} else {
|
||||
return ' ';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'targets': 2,
|
||||
'data': 'authenticated_principal',
|
||||
'className': 'col-xs-4 col-md-2',
|
||||
'render': function (data, type) {
|
||||
return type === 'display' && data.length > 20 ?
|
||||
'<span title="' + data + '">' + data.substr(0, 18) + '...</span>' :
|
||||
data;
|
||||
}
|
||||
},
|
||||
{
|
||||
'targets': 3,
|
||||
'data': 'ticket_granting_ticket',
|
||||
'className': 'hidden-xs hidden-sm col-md-4',
|
||||
'render': function (data, type) {
|
||||
return type === 'display' && data.length > 20 ?
|
||||
'<span title="' + data + '">' + data.substr(0, 40) + '...</span>' :
|
||||
data;
|
||||
}
|
||||
},
|
||||
{
|
||||
'targets': 4,
|
||||
'data': 'authentication_date_formatted',
|
||||
'className': 'col-xs-4 col-sm-4 col-md-2'
|
||||
},
|
||||
{
|
||||
'targets': 5,
|
||||
'data': 'number_of_uses',
|
||||
'className': 'hidden-xs hidden-sm visible-md-* col-md-2'
|
||||
},
|
||||
{
|
||||
'targets': 6,
|
||||
'data': 'ticket_granting_ticket',
|
||||
'className': 'col-xs-2 col-sm-2 col-md-1',
|
||||
'render': function (data) {
|
||||
return '<button class="btn btn-xs btn-block btn-danger" type="button" value="' + data + '">Destroy</button>';
|
||||
},
|
||||
'orderable': false
|
||||
},
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
var addEventHandlers = function () {
|
||||
|
||||
/**
|
||||
* The Bulk remove button
|
||||
*/
|
||||
$('#removeAllSessionsButton').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
removeSession(this.value);
|
||||
});
|
||||
|
||||
/**
|
||||
* Individual removal button
|
||||
*/
|
||||
$(document).on('click', '#ssoSessions tbody tr td:last-child button.btn-danger', function (e) {
|
||||
e.preventDefault();
|
||||
removeSession(this.value);
|
||||
});
|
||||
|
||||
/**
|
||||
* The filter buttons
|
||||
*/
|
||||
$('#filterButtons .btn').click(function () {
|
||||
|
||||
var filter = $(this).data('filter');
|
||||
var table = $('#ssoSessions').DataTable();
|
||||
var filterRegex;
|
||||
var deleteValue;
|
||||
var btnText;
|
||||
|
||||
// Create Filter RegEx:
|
||||
if (filter == 'proxied') {
|
||||
filterRegex = '^Proxy$';
|
||||
deleteValue = 'PROXIED';
|
||||
btnText = 'Remove <span class="badge">xx</span> Proxied Sessions';
|
||||
} else if (filter == 'non-proxied') {
|
||||
filterRegex = '^ $';
|
||||
deleteValue = 'DIRECT';
|
||||
btnText = 'Remove <span class="badge">xx</span> Non-Proxied Sessions';
|
||||
} else {
|
||||
filterRegex = '';
|
||||
deleteValue = 'ALL';
|
||||
btnText = 'Remove All Sessions';
|
||||
}
|
||||
|
||||
var searchTerm = table.column(1).search(filterRegex, true, false).draw();
|
||||
|
||||
$('#removeAllSessionsButton').val(deleteValue).html(btnText.replace('xx', searchTerm.page.info().recordsDisplay));
|
||||
});
|
||||
|
||||
|
||||
// Add event listener for opening and closing details
|
||||
$(document).on('click', '#ssoSessions tbody td.details-control', function () {
|
||||
var table = $('#ssoSessions').DataTable();
|
||||
var tr = $(this).closest('tr');
|
||||
var row = table.row(tr);
|
||||
|
||||
if (row.child.isShown()) {
|
||||
// This row is already open - close it
|
||||
row.child.hide();
|
||||
tr.removeClass('shown');
|
||||
}
|
||||
else {
|
||||
// Open this row
|
||||
row.child(format(row.data()), 'info').show();
|
||||
tr.addClass('shown');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// initialization *******
|
||||
(function init() {
|
||||
addEventHandlers();
|
||||
createDataTable();
|
||||
})();
|
||||
|
||||
// Public Methods
|
||||
return {
|
||||
/**
|
||||
* Not used
|
||||
*/
|
||||
};
|
||||
})();
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/* global d3 */
|
||||
/*eslint-disable no-unused-vars*/
|
||||
var Gauge = function (wrapper, percent, options) {
|
||||
if (!wrapper || !percent) {
|
||||
//console.error('wrapper and percentage are required. Please check your code.');
|
||||
return;
|
||||
}
|
||||
|
||||
var label = (!options.label) ? '' : options.label;
|
||||
|
||||
var textClass = options.textClass || 'progress-meter';
|
||||
|
||||
var width = options.width || 200,
|
||||
height = options.height || 200,
|
||||
twoPi = 2 * Math.PI,
|
||||
progress = 0,
|
||||
total = 100,
|
||||
formatPercent = d3.format('.0%');
|
||||
|
||||
var colorScale = d3.scaleLinear()
|
||||
.domain([0, 0.40, 0.50, 1])
|
||||
.range(['green', 'green', 'goldenrod', 'red']);
|
||||
|
||||
var arc = d3.arc()
|
||||
.startAngle(0)
|
||||
.innerRadius(width * 0.4)
|
||||
.outerRadius(width * 0.5)
|
||||
;
|
||||
|
||||
var svg = d3.select(wrapper).append('svg')
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
|
||||
.attr('fill', '#2E7AF9')
|
||||
.append('g')
|
||||
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
|
||||
|
||||
var meter = svg.append('g')
|
||||
.attr('class', textClass);
|
||||
|
||||
meter.append('path')
|
||||
.attr('class', 'background')
|
||||
.attr('d', arc.endAngle(twoPi));
|
||||
|
||||
var foreground = meter.append('path')
|
||||
.attr('class', 'foreground');
|
||||
|
||||
var text = meter.append('text')
|
||||
.attr('text-anchor', 'middle');
|
||||
|
||||
var text2 = meter.append('text')
|
||||
.attr('y', height * 0.15)
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('class', 'text2');
|
||||
|
||||
text2.text(label);
|
||||
|
||||
var animate = function (percentage) {
|
||||
var i = d3.interpolate(progress, percentage);
|
||||
|
||||
foreground.transition().duration(2000)
|
||||
.tween('progress', function () {
|
||||
|
||||
return function (t) {
|
||||
progress = i(t);
|
||||
|
||||
foreground.style('fill', colorScale(progress));
|
||||
foreground.attr('d', arc.endAngle(twoPi * progress));
|
||||
text.text(formatPercent(progress));
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// init
|
||||
(function () {
|
||||
setTimeout(function () {
|
||||
animate(percent);
|
||||
}, 500);
|
||||
})();
|
||||
|
||||
return {
|
||||
update: function (newPercent) {
|
||||
animate(newPercent);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function upTime(countTo, el) {
|
||||
var wrapper = document.getElementById('card-uptime');
|
||||
var element = document.getElementById(el);
|
||||
var difference = new Date(countTo*1000);
|
||||
|
||||
var days = Math.floor(difference / (60 * 60 * 1000 * 24) * 1);
|
||||
var hours = Math.floor((difference % (60 * 60 * 1000 * 24)) / (60 * 60 * 1000) * 1);
|
||||
var mins = Math.floor(((difference % (60 * 60 * 1000 * 24)) % (60 * 60 * 1000)) / (60 * 1000) * 1);
|
||||
var secs = Math.floor((((difference % (60 * 60 * 1000 * 24)) % (60 * 60 * 1000)) % (60 * 1000)) / 1000 * 1);
|
||||
|
||||
clearTimeout(upTime.to);
|
||||
|
||||
if (isNaN(days) || isNaN(hours) || isNaN(mins) || isNaN(secs) ) {
|
||||
wrapper.style.display = 'none';
|
||||
} else {
|
||||
days = (days == 1) ? days + ' day ' : days + ' days ';
|
||||
hours = (hours == 1) ? hours + ' hour ' : hours + ' hours ';
|
||||
mins = (mins == 1) ? mins + ' minute ' : mins + ' minutes ';
|
||||
secs = (secs == 1) ? secs + ' second ' : secs + ' seconds';
|
||||
|
||||
var timeString = '<span class="upTime">' + days + hours + mins + secs + '</span>';
|
||||
element.innerHTML = timeString;
|
||||
wrapper.style.display = 'block';
|
||||
|
||||
upTime.to = setTimeout(function() {
|
||||
countTo = countTo + 1;
|
||||
upTime(countTo, el);
|
||||
},1000);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var analytics = document.getElementById('expiredSts');
|
||||
|
||||
var casStatistics = function (urls, messages) {
|
||||
var timers = {
|
||||
memory: 5000,
|
||||
availability: 15000,
|
||||
tickets: 5000
|
||||
};
|
||||
|
||||
var memoryGauage;
|
||||
|
||||
var getRemoteJSON = function(url) {
|
||||
return $.getJSON( url);
|
||||
};
|
||||
|
||||
var tickets = function() {
|
||||
var data = getRemoteJSON(urls.tickets);
|
||||
data.done(function( data ) {
|
||||
updateElementValue( 'unexpiredTgts', data.unexpiredTgts );
|
||||
updateElementValue( 'unexpiredSts', data.unexpiredSts );
|
||||
updateElementValue( 'expiredTgts', data.expiredTgts );
|
||||
updateElementValue( 'expiredSts', data.expiredSts );
|
||||
setTimeout( tickets, timers.tickets );
|
||||
});
|
||||
};
|
||||
|
||||
var updateElementValue = function(el, val) {
|
||||
$( '#' + el ).text( val );
|
||||
};
|
||||
|
||||
var memory = function() {
|
||||
var data = getRemoteJSON(urls.memory);
|
||||
data.done(function( data ) {
|
||||
updateElementValue('freeMemory', data.freeMemory.toFixed(2));
|
||||
// updateElementValue('totalMemory', data.totalMemory);
|
||||
// updateElementValue('maxMemory', data.maxMemory);
|
||||
// updateElementValue('availableProcessors', data.availableProcessors);
|
||||
|
||||
var memCalc = (data.totalMemory / data.maxMemory).toFixed(2);
|
||||
|
||||
if ( !memoryGauage ) {
|
||||
memoryGauage = new Gauge('#maxMemoryGauge', memCalc, {width: 200, height: 200,
|
||||
label: messages.memoryGaugeTitle,
|
||||
textClass: 'runtimeStatistics'});
|
||||
} else {
|
||||
memoryGauage.update( memCalc );
|
||||
}
|
||||
|
||||
setTimeout( memory, timers.memory );
|
||||
});
|
||||
|
||||
};
|
||||
var availability = function() {
|
||||
var data = getRemoteJSON(urls.availability);
|
||||
data.done(function( data ) {
|
||||
updateElementValue('upTime', data.upTime);
|
||||
setTimeout( availability, timers.availability );
|
||||
});
|
||||
};
|
||||
|
||||
// initialization *******
|
||||
( function init () {
|
||||
$('#loading, .statisticsView').toggle();
|
||||
tickets();
|
||||
memory();
|
||||
// availability();
|
||||
})();
|
||||
|
||||
// Public Methods
|
||||
return {
|
||||
getTickets: function() {
|
||||
return tickets();
|
||||
},
|
||||
getMemory: function() {
|
||||
return memory();
|
||||
},
|
||||
getAvailability: function() {
|
||||
return availability();
|
||||
},
|
||||
updateGauge: function(val){
|
||||
if (memoryGauage) {
|
||||
memoryGauage.update( val );
|
||||
} else {
|
||||
return 'unable to update';
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
+474
@@ -0,0 +1,474 @@
|
||||
// Generated by CoffeeScript 1.7.1
|
||||
|
||||
/*
|
||||
Stomp Over WebSocket http://www.jmesnil.net/stomp-websocket/doc/ | Apache License V2.0
|
||||
|
||||
Copyright (C) 2010-2013 [Jeff Mesnil](http://jmesnil.net/)
|
||||
Copyright (C) 2012 [FuseSource, Inc.](http://fusesource.com)
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var Byte, Client, Frame, Stomp,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__slice = [].slice;
|
||||
|
||||
Byte = {
|
||||
LF: '\x0A',
|
||||
NULL: '\x00'
|
||||
};
|
||||
|
||||
Frame = (function() {
|
||||
var unmarshallSingle;
|
||||
|
||||
function Frame(command, headers, body) {
|
||||
this.command = command;
|
||||
this.headers = headers != null ? headers : {};
|
||||
this.body = body != null ? body : '';
|
||||
}
|
||||
|
||||
Frame.prototype.toString = function() {
|
||||
var lines, name, value, _ref;
|
||||
lines = [this.command];
|
||||
_ref = this.headers;
|
||||
for (name in _ref) {
|
||||
if (!__hasProp.call(_ref, name)) continue;
|
||||
value = _ref[name];
|
||||
lines.push("" + name + ":" + value);
|
||||
}
|
||||
if (this.body) {
|
||||
lines.push("content-length:" + (Frame.sizeOfUTF8(this.body)));
|
||||
}
|
||||
lines.push(Byte.LF + this.body);
|
||||
return lines.join(Byte.LF);
|
||||
};
|
||||
|
||||
Frame.sizeOfUTF8 = function(s) {
|
||||
if (s) {
|
||||
return encodeURI(s).split(/%..|./).length - 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
unmarshallSingle = function(data) {
|
||||
var body, chr, command, divider, headerLines, headers, i, idx, len, line, start, trim, _i, _j, _len, _ref, _ref1;
|
||||
divider = data.search(RegExp("" + Byte.LF + Byte.LF));
|
||||
headerLines = data.substring(0, divider).split(Byte.LF);
|
||||
command = headerLines.shift();
|
||||
headers = {};
|
||||
trim = function(str) {
|
||||
return str.replace(/^\s+|\s+$/g, '');
|
||||
};
|
||||
_ref = headerLines.reverse();
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
line = _ref[_i];
|
||||
idx = line.indexOf(':');
|
||||
headers[trim(line.substring(0, idx))] = trim(line.substring(idx + 1));
|
||||
}
|
||||
body = '';
|
||||
start = divider + 2;
|
||||
if (headers['content-length']) {
|
||||
len = parseInt(headers['content-length']);
|
||||
body = ('' + data).substring(start, start + len);
|
||||
} else {
|
||||
chr = null;
|
||||
for (i = _j = start, _ref1 = data.length; start <= _ref1 ? _j < _ref1 : _j > _ref1; i = start <= _ref1 ? ++_j : --_j) {
|
||||
chr = data.charAt(i);
|
||||
if (chr === Byte.NULL) {
|
||||
break;
|
||||
}
|
||||
body += chr;
|
||||
}
|
||||
}
|
||||
return new Frame(command, headers, body);
|
||||
};
|
||||
|
||||
Frame.unmarshall = function(datas) {
|
||||
var data;
|
||||
return (function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = datas.split(RegExp("" + Byte.NULL + Byte.LF + "*"));
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
data = _ref[_i];
|
||||
if ((data != null ? data.length : void 0) > 0) {
|
||||
_results.push(unmarshallSingle(data));
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
};
|
||||
|
||||
Frame.marshall = function(command, headers, body) {
|
||||
var frame;
|
||||
frame = new Frame(command, headers, body);
|
||||
return frame.toString() + Byte.NULL;
|
||||
};
|
||||
|
||||
return Frame;
|
||||
|
||||
})();
|
||||
|
||||
Client = (function() {
|
||||
var now;
|
||||
|
||||
function Client(ws) {
|
||||
this.ws = ws;
|
||||
this.ws.binaryType = "arraybuffer";
|
||||
this.counter = 0;
|
||||
this.connected = false;
|
||||
this.heartbeat = {
|
||||
outgoing: 10000,
|
||||
incoming: 10000
|
||||
};
|
||||
this.maxWebSocketFrameSize = 16 * 1024;
|
||||
this.subscriptions = {};
|
||||
}
|
||||
|
||||
Client.prototype.debug = function(message) {
|
||||
void 0;
|
||||
};
|
||||
|
||||
now = function() {
|
||||
return Date.now || new Date().valueOf;
|
||||
};
|
||||
|
||||
Client.prototype._transmit = function(command, headers, body) {
|
||||
var out;
|
||||
out = Frame.marshall(command, headers, body);
|
||||
if (typeof this.debug === "function") {
|
||||
this.debug(">>> " + out);
|
||||
}
|
||||
while (true) {
|
||||
if (out.length > this.maxWebSocketFrameSize) {
|
||||
this.ws.send(out.substring(0, this.maxWebSocketFrameSize));
|
||||
out = out.substring(this.maxWebSocketFrameSize);
|
||||
if (typeof this.debug === "function") {
|
||||
this.debug("remaining = " + out.length);
|
||||
}
|
||||
} else {
|
||||
return this.ws.send(out);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Client.prototype._setupHeartbeat = function(headers) {
|
||||
var serverIncoming, serverOutgoing, ttl, v, _ref, _ref1;
|
||||
if ((_ref = headers.version) !== Stomp.VERSIONS.V1_1 && _ref !== Stomp.VERSIONS.V1_2) {
|
||||
return;
|
||||
}
|
||||
_ref1 = (function() {
|
||||
var _i, _len, _ref1, _results;
|
||||
_ref1 = headers['heart-beat'].split(",");
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||
v = _ref1[_i];
|
||||
_results.push(parseInt(v));
|
||||
}
|
||||
return _results;
|
||||
})(), serverOutgoing = _ref1[0], serverIncoming = _ref1[1];
|
||||
if (!(this.heartbeat.outgoing === 0 || serverIncoming === 0)) {
|
||||
ttl = Math.max(this.heartbeat.outgoing, serverIncoming);
|
||||
if (typeof this.debug === "function") {
|
||||
this.debug("send PING every " + ttl + "ms");
|
||||
}
|
||||
this.pinger = Stomp.setInterval(ttl, (function(_this) {
|
||||
return function() {
|
||||
_this.ws.send(Byte.LF);
|
||||
return typeof _this.debug === "function" ? _this.debug(">>> PING") : void 0;
|
||||
};
|
||||
})(this));
|
||||
}
|
||||
if (!(this.heartbeat.incoming === 0 || serverOutgoing === 0)) {
|
||||
ttl = Math.max(this.heartbeat.incoming, serverOutgoing);
|
||||
if (typeof this.debug === "function") {
|
||||
this.debug("check PONG every " + ttl + "ms");
|
||||
}
|
||||
return this.ponger = Stomp.setInterval(ttl, (function(_this) {
|
||||
return function() {
|
||||
var delta;
|
||||
delta = now() - _this.serverActivity;
|
||||
if (delta > ttl * 2) {
|
||||
if (typeof _this.debug === "function") {
|
||||
_this.debug("did not receive server activity for the last " + delta + "ms");
|
||||
}
|
||||
return _this.ws.close();
|
||||
}
|
||||
};
|
||||
})(this));
|
||||
}
|
||||
};
|
||||
|
||||
Client.prototype._parseConnect = function() {
|
||||
var args, connectCallback, errorCallback, headers;
|
||||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
||||
headers = {};
|
||||
switch (args.length) {
|
||||
case 2:
|
||||
headers = args[0], connectCallback = args[1];
|
||||
break;
|
||||
case 3:
|
||||
if (args[1] instanceof Function) {
|
||||
headers = args[0], connectCallback = args[1], errorCallback = args[2];
|
||||
} else {
|
||||
headers.login = args[0], headers.passcode = args[1], connectCallback = args[2];
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3];
|
||||
break;
|
||||
default:
|
||||
headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3], headers.host = args[4];
|
||||
}
|
||||
return [headers, connectCallback, errorCallback];
|
||||
};
|
||||
|
||||
Client.prototype.connect = function() {
|
||||
var args, errorCallback, headers, out;
|
||||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
||||
out = this._parseConnect.apply(this, args);
|
||||
headers = out[0], this.connectCallback = out[1], errorCallback = out[2];
|
||||
if (typeof this.debug === "function") {
|
||||
this.debug("Opening Web Socket...");
|
||||
}
|
||||
this.ws.onmessage = (function(_this) {
|
||||
return function(evt) {
|
||||
var arr, c, client, data, frame, messageID, onreceive, subscription, _i, _len, _ref, _results;
|
||||
data = typeof ArrayBuffer !== 'undefined' && evt.data instanceof ArrayBuffer ? (arr = new Uint8Array(evt.data), typeof _this.debug === "function" ? _this.debug("--- got data length: " + arr.length) : void 0, ((function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = arr.length; _i < _len; _i++) {
|
||||
c = arr[_i];
|
||||
_results.push(String.fromCharCode(c));
|
||||
}
|
||||
return _results;
|
||||
})()).join('')) : evt.data;
|
||||
_this.serverActivity = now();
|
||||
if (data === Byte.LF) {
|
||||
if (typeof _this.debug === "function") {
|
||||
_this.debug("<<< PONG");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (typeof _this.debug === "function") {
|
||||
_this.debug("<<< " + data);
|
||||
}
|
||||
_ref = Frame.unmarshall(data);
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
frame = _ref[_i];
|
||||
switch (frame.command) {
|
||||
case "CONNECTED":
|
||||
if (typeof _this.debug === "function") {
|
||||
_this.debug("connected to server " + frame.headers.server);
|
||||
}
|
||||
_this.connected = true;
|
||||
_this._setupHeartbeat(frame.headers);
|
||||
_results.push(typeof _this.connectCallback === "function" ? _this.connectCallback(frame) : void 0);
|
||||
break;
|
||||
case "MESSAGE":
|
||||
subscription = frame.headers.subscription;
|
||||
onreceive = _this.subscriptions[subscription] || _this.onreceive;
|
||||
if (onreceive) {
|
||||
client = _this;
|
||||
messageID = frame.headers["message-id"];
|
||||
frame.ack = function(headers) {
|
||||
if (headers == null) {
|
||||
headers = {};
|
||||
}
|
||||
return client.ack(messageID, subscription, headers);
|
||||
};
|
||||
frame.nack = function(headers) {
|
||||
if (headers == null) {
|
||||
headers = {};
|
||||
}
|
||||
return client.nack(messageID, subscription, headers);
|
||||
};
|
||||
_results.push(onreceive(frame));
|
||||
} else {
|
||||
_results.push(typeof _this.debug === "function" ? _this.debug("Unhandled received MESSAGE: " + frame) : void 0);
|
||||
}
|
||||
break;
|
||||
case "RECEIPT":
|
||||
_results.push(typeof _this.onreceipt === "function" ? _this.onreceipt(frame) : void 0);
|
||||
break;
|
||||
case "ERROR":
|
||||
_results.push(typeof errorCallback === "function" ? errorCallback(frame) : void 0);
|
||||
break;
|
||||
default:
|
||||
_results.push(typeof _this.debug === "function" ? _this.debug("Unhandled frame: " + frame) : void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
})(this);
|
||||
this.ws.onclose = (function(_this) {
|
||||
return function() {
|
||||
var msg;
|
||||
msg = "Whoops! Lost connection to " + _this.ws.url;
|
||||
if (typeof _this.debug === "function") {
|
||||
_this.debug(msg);
|
||||
}
|
||||
_this._cleanUp();
|
||||
return typeof errorCallback === "function" ? errorCallback(msg) : void 0;
|
||||
};
|
||||
})(this);
|
||||
return this.ws.onopen = (function(_this) {
|
||||
return function() {
|
||||
if (typeof _this.debug === "function") {
|
||||
_this.debug('Web Socket Opened...');
|
||||
}
|
||||
headers["accept-version"] = Stomp.VERSIONS.supportedVersions();
|
||||
headers["heart-beat"] = [_this.heartbeat.outgoing, _this.heartbeat.incoming].join(',');
|
||||
return _this._transmit("CONNECT", headers);
|
||||
};
|
||||
})(this);
|
||||
};
|
||||
|
||||
Client.prototype.disconnect = function(disconnectCallback) {
|
||||
this._transmit("DISCONNECT");
|
||||
this.ws.onclose = null;
|
||||
this.ws.close();
|
||||
this._cleanUp();
|
||||
return typeof disconnectCallback === "function" ? disconnectCallback() : void 0;
|
||||
};
|
||||
|
||||
Client.prototype._cleanUp = function() {
|
||||
this.connected = false;
|
||||
if (this.pinger) {
|
||||
Stomp.clearInterval(this.pinger);
|
||||
}
|
||||
if (this.ponger) {
|
||||
return Stomp.clearInterval(this.ponger);
|
||||
}
|
||||
};
|
||||
|
||||
Client.prototype.send = function(destination, headers, body) {
|
||||
if (headers == null) {
|
||||
headers = {};
|
||||
}
|
||||
if (body == null) {
|
||||
body = '';
|
||||
}
|
||||
headers.destination = destination;
|
||||
return this._transmit("SEND", headers, body);
|
||||
};
|
||||
|
||||
Client.prototype.subscribe = function(destination, callback, headers) {
|
||||
var client;
|
||||
if (headers == null) {
|
||||
headers = {};
|
||||
}
|
||||
if (!headers.id) {
|
||||
headers.id = "sub-" + this.counter++;
|
||||
}
|
||||
headers.destination = destination;
|
||||
this.subscriptions[headers.id] = callback;
|
||||
this._transmit("SUBSCRIBE", headers);
|
||||
client = this;
|
||||
return {
|
||||
id: headers.id,
|
||||
unsubscribe: function() {
|
||||
return client.unsubscribe(headers.id);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Client.prototype.unsubscribe = function(id) {
|
||||
delete this.subscriptions[id];
|
||||
return this._transmit("UNSUBSCRIBE", {
|
||||
id: id
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.begin = function(transaction) {
|
||||
var client, txid;
|
||||
txid = transaction || "tx-" + this.counter++;
|
||||
this._transmit("BEGIN", {
|
||||
transaction: txid
|
||||
});
|
||||
client = this;
|
||||
return {
|
||||
id: txid,
|
||||
commit: function() {
|
||||
return client.commit(txid);
|
||||
},
|
||||
abort: function() {
|
||||
return client.abort(txid);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Client.prototype.commit = function(transaction) {
|
||||
return this._transmit("COMMIT", {
|
||||
transaction: transaction
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.abort = function(transaction) {
|
||||
return this._transmit("ABORT", {
|
||||
transaction: transaction
|
||||
});
|
||||
};
|
||||
|
||||
Client.prototype.ack = function(messageID, subscription, headers) {
|
||||
if (headers == null) {
|
||||
headers = {};
|
||||
}
|
||||
headers["message-id"] = messageID;
|
||||
headers.subscription = subscription;
|
||||
return this._transmit("ACK", headers);
|
||||
};
|
||||
|
||||
Client.prototype.nack = function(messageID, subscription, headers) {
|
||||
if (headers == null) {
|
||||
headers = {};
|
||||
}
|
||||
headers["message-id"] = messageID;
|
||||
headers.subscription = subscription;
|
||||
return this._transmit("NACK", headers);
|
||||
};
|
||||
|
||||
return Client;
|
||||
|
||||
})();
|
||||
|
||||
Stomp = {
|
||||
VERSIONS: {
|
||||
V1_0: '1.0',
|
||||
V1_1: '1.1',
|
||||
V1_2: '1.2',
|
||||
supportedVersions: function() {
|
||||
return '1.1,1.0';
|
||||
}
|
||||
},
|
||||
client: function(url, protocols) {
|
||||
var klass, ws;
|
||||
if (protocols == null) {
|
||||
protocols = ['v10.stomp', 'v11.stomp'];
|
||||
}
|
||||
klass = Stomp.WebSocketClass || WebSocket;
|
||||
ws = new klass(url, protocols);
|
||||
return new Client(ws);
|
||||
},
|
||||
over: function(ws) {
|
||||
return new Client(ws);
|
||||
},
|
||||
Frame: Frame
|
||||
};
|
||||
|
||||
if (typeof window !== "undefined" && window !== null) {
|
||||
Stomp.setInterval = function(interval, f) {
|
||||
return window.setInterval(f, interval);
|
||||
};
|
||||
Stomp.clearInterval = function(id) {
|
||||
return window.clearInterval(id);
|
||||
};
|
||||
window.Stomp = Stomp;
|
||||
} else if (typeof exports !== "undefined" && exports !== null) {
|
||||
exports.Stomp = Stomp;
|
||||
} else {
|
||||
self.Stomp = Stomp;
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*eslint-disable no-unused-vars*/
|
||||
$('#myTabs a').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).tab('show');
|
||||
});
|
||||
|
||||
var revokeDevice = function (key) {
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
url: urls.revokeRecord,
|
||||
data: {'key': key},
|
||||
success: function () {
|
||||
var table = $('#trustedDevicesTable').DataTable();
|
||||
table
|
||||
.rows($('#' + key).parents('tr'))
|
||||
.remove()
|
||||
.draw();
|
||||
},
|
||||
error: function () {
|
||||
//console.log('Could not remove record');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var trustedDevices = (function () {
|
||||
var getData = function () {
|
||||
$.getJSON(urls.getRecords, function (data) {
|
||||
trustedDevicesTable(data);
|
||||
});
|
||||
};
|
||||
|
||||
var trustedDevicesTable = function (jsonData) {
|
||||
var t = $('#trustedDevicesTable').DataTable({
|
||||
'order': [[2, 'desc']],
|
||||
columnDefs: [
|
||||
{'width': '20%', 'targets': 0},
|
||||
{'width': '10%', 'targets': 1},
|
||||
{'width': '60%', 'targets': 2},
|
||||
{'width': '10%', 'targets': 3},
|
||||
{'width': '30%', 'targets': 4}
|
||||
]
|
||||
});
|
||||
for (var i = 0; i < jsonData.length; i++) {
|
||||
var rec = jsonData[i];
|
||||
t.row.add([
|
||||
rec.name,
|
||||
rec.principal,
|
||||
new Date(rec.date),
|
||||
rec.geography,
|
||||
'<button id=\'' + rec.key + '\' class=\'btn btn-sm btn-danger\' type=\'button\' value=\'ALL\' onclick=\'revokeDevice("' + rec.key + '")\'>Revoke</button>'
|
||||
]).draw(false);
|
||||
}
|
||||
};
|
||||
|
||||
// initialization *******
|
||||
(function init() {
|
||||
getData();
|
||||
})();
|
||||
})();
|
||||
+748
@@ -0,0 +1,748 @@
|
||||
//Copyright 2014-2015 Google Inc. All rights reserved.
|
||||
|
||||
//Use of this source code is governed by a BSD-style
|
||||
//license that can be found in the LICENSE file or at
|
||||
//https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
/**
|
||||
* @fileoverview The U2F api.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
||||
/**
|
||||
* Namespace for the U2F api.
|
||||
* @type {Object}
|
||||
*/
|
||||
var u2f = u2f || {};
|
||||
|
||||
/**
|
||||
* FIDO U2F Javascript API Version
|
||||
* @number
|
||||
*/
|
||||
var js_api_version;
|
||||
|
||||
/**
|
||||
* The U2F extension id
|
||||
* @const {string}
|
||||
*/
|
||||
// The Chrome packaged app extension ID.
|
||||
// Uncomment this if you want to deploy a server instance that uses
|
||||
// the package Chrome app and does not require installing the U2F Chrome extension.
|
||||
u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
|
||||
// The U2F Chrome extension ID.
|
||||
// Uncomment this if you want to deploy a server instance that uses
|
||||
// the U2F Chrome extension to authenticate.
|
||||
// u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
|
||||
|
||||
|
||||
/**
|
||||
* Message types for messsages to/from the extension
|
||||
* @const
|
||||
* @enum {string}
|
||||
*/
|
||||
u2f.MessageTypes = {
|
||||
'U2F_REGISTER_REQUEST': 'u2f_register_request',
|
||||
'U2F_REGISTER_RESPONSE': 'u2f_register_response',
|
||||
'U2F_SIGN_REQUEST': 'u2f_sign_request',
|
||||
'U2F_SIGN_RESPONSE': 'u2f_sign_response',
|
||||
'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
|
||||
'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Response status codes
|
||||
* @const
|
||||
* @enum {number}
|
||||
*/
|
||||
u2f.ErrorCodes = {
|
||||
'OK': 0,
|
||||
'OTHER_ERROR': 1,
|
||||
'BAD_REQUEST': 2,
|
||||
'CONFIGURATION_UNSUPPORTED': 3,
|
||||
'DEVICE_INELIGIBLE': 4,
|
||||
'TIMEOUT': 5
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A message for registration requests
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* appId: ?string,
|
||||
* timeoutSeconds: ?number,
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.U2fRequest;
|
||||
|
||||
|
||||
/**
|
||||
* A message for registration responses
|
||||
* @typedef {{
|
||||
* type: u2f.MessageTypes,
|
||||
* responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
|
||||
* requestId: ?number
|
||||
* }}
|
||||
*/
|
||||
u2f.U2fResponse;
|
||||
|
||||
|
||||
/**
|
||||
* An error object for responses
|
||||
* @typedef {{
|
||||
* errorCode: u2f.ErrorCodes,
|
||||
* errorMessage: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.Error;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}}
|
||||
*/
|
||||
u2f.Transport;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {Array<u2f.Transport>}
|
||||
*/
|
||||
u2f.Transports;
|
||||
|
||||
/**
|
||||
* Data object for a single sign request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string,
|
||||
* keyHandle: string,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a sign response.
|
||||
* @typedef {{
|
||||
* keyHandle: string,
|
||||
* signatureData: string,
|
||||
* clientData: string
|
||||
* }}
|
||||
*/
|
||||
u2f.SignResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registration request.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* challenge: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registration response.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* keyHandle: string,
|
||||
* transports: Transports,
|
||||
* appId: string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisterResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a registered key.
|
||||
* @typedef {{
|
||||
* version: string,
|
||||
* keyHandle: string,
|
||||
* transports: ?Transports,
|
||||
* appId: ?string
|
||||
* }}
|
||||
*/
|
||||
u2f.RegisteredKey;
|
||||
|
||||
|
||||
/**
|
||||
* Data object for a get API register response.
|
||||
* @typedef {{
|
||||
* js_api_version: number
|
||||
* }}
|
||||
*/
|
||||
u2f.GetJsApiVersionResponse;
|
||||
|
||||
|
||||
//Low level MessagePort API support
|
||||
|
||||
/**
|
||||
* Sets up a MessagePort to the U2F extension using the
|
||||
* available mechanisms.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
*/
|
||||
u2f.getMessagePort = function(callback) {
|
||||
if (typeof chrome != 'undefined' && chrome.runtime) {
|
||||
// The actual message here does not matter, but we need to get a reply
|
||||
// for the callback to run. Thus, send an empty signature request
|
||||
// in order to get a failure response.
|
||||
var msg = {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: []
|
||||
};
|
||||
chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() {
|
||||
if (!chrome.runtime.lastError) {
|
||||
// We are on a whitelisted origin and can talk directly
|
||||
// with the extension.
|
||||
u2f.getChromeRuntimePort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was available, but we couldn't message
|
||||
// the extension directly, use iframe
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
});
|
||||
} else if (u2f.isAndroidChrome_()) {
|
||||
u2f.getAuthenticatorPort_(callback);
|
||||
} else if (u2f.isIosChrome_()) {
|
||||
u2f.getIosPort_(callback);
|
||||
} else {
|
||||
// chrome.runtime was not available at all, which is normal
|
||||
// when this origin doesn't have access to any extensions.
|
||||
u2f.getIframePort_(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on android based on the browser's useragent.
|
||||
* @private
|
||||
*/
|
||||
u2f.isAndroidChrome_ = function() {
|
||||
var userAgent = navigator.userAgent;
|
||||
return userAgent.indexOf('Chrome') != -1 &&
|
||||
userAgent.indexOf('Android') != -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect chrome running on iOS based on the browser's platform.
|
||||
* @private
|
||||
*/
|
||||
u2f.isIosChrome_ = function() {
|
||||
return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects directly to the extension via chrome.runtime.connect.
|
||||
* @param {function(u2f.WrappedChromeRuntimePort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getChromeRuntimePort_ = function(callback) {
|
||||
var port = chrome.runtime.connect(u2f.EXTENSION_ID,
|
||||
{'includeTlsChannelId': true});
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedChromeRuntimePort_(port));
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the Authenticator app.
|
||||
* @param {function(u2f.WrappedAuthenticatorPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getAuthenticatorPort_ = function(callback) {
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedAuthenticatorPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a 'port' abstraction to the iOS client app.
|
||||
* @param {function(u2f.WrappedIosPort_)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIosPort_ = function(callback) {
|
||||
setTimeout(function() {
|
||||
callback(new u2f.WrappedIosPort_());
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper for chrome.runtime.Port that is compatible with MessagePort.
|
||||
* @param {Port} port
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_ = function(port) {
|
||||
this.port_ = port;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format and return a sign request compliant with the JS API version supported by the extension.
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.formatSignRequest_ =
|
||||
function(appId, challenge, registeredKeys, timeoutSeconds, reqId) {
|
||||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||||
// Adapt request to the 1.0 JS API
|
||||
var signRequests = [];
|
||||
for (var i = 0; i < registeredKeys.length; i++) {
|
||||
signRequests[i] = {
|
||||
version: registeredKeys[i].version,
|
||||
challenge: challenge,
|
||||
keyHandle: registeredKeys[i].keyHandle,
|
||||
appId: appId
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
signRequests: signRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
}
|
||||
// JS 1.1 API
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||||
appId: appId,
|
||||
challenge: challenge,
|
||||
registeredKeys: registeredKeys,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Format and return a register request compliant with the JS API version supported by the extension..
|
||||
* @param {Array<u2f.SignRequest>} signRequests
|
||||
* @param {Array<u2f.RegisterRequest>} signRequests
|
||||
* @param {number} timeoutSeconds
|
||||
* @param {number} reqId
|
||||
* @return {Object}
|
||||
*/
|
||||
u2f.formatRegisterRequest_ =
|
||||
function(appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
|
||||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||||
// Adapt request to the 1.0 JS API
|
||||
for (var i = 0; i < registerRequests.length; i++) {
|
||||
registerRequests[i].appId = appId;
|
||||
}
|
||||
var signRequests = [];
|
||||
for (var i = 0; i < registeredKeys.length; i++) {
|
||||
signRequests[i] = {
|
||||
version: registeredKeys[i].version,
|
||||
challenge: registerRequests[0],
|
||||
keyHandle: registeredKeys[i].keyHandle,
|
||||
appId: appId
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
signRequests: signRequests,
|
||||
registerRequests: registerRequests,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
}
|
||||
// JS 1.1 API
|
||||
return {
|
||||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||||
appId: appId,
|
||||
registerRequests: registerRequests,
|
||||
registeredKeys: registeredKeys,
|
||||
timeoutSeconds: timeoutSeconds,
|
||||
requestId: reqId
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Posts a message on the underlying channel.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) {
|
||||
this.port_.postMessage(message);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface. Works only for the
|
||||
* onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
|
||||
function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message' || name == 'onmessage') {
|
||||
this.port_.onMessage.addListener(function(message) {
|
||||
// Emulate a minimal MessageEvent object
|
||||
handler({'data': message});
|
||||
});
|
||||
} else {
|
||||
console.error('WrappedChromeRuntimePort only supports onMessage');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap the Authenticator app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_ = function() {
|
||||
this.requestId_ = -1;
|
||||
this.requestObject_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the Authenticator intent.
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.postMessage = function(message) {
|
||||
var intentUrl =
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
|
||||
';S.request=' + encodeURIComponent(JSON.stringify(message)) +
|
||||
';end';
|
||||
document.location = intentUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells what type of port this is.
|
||||
* @return {String} port type
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.getPortType = function() {
|
||||
return "WrappedAuthenticatorPort_";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name == 'message') {
|
||||
var self = this;
|
||||
/* Register a callback to that executes when
|
||||
* chrome injects the response. */
|
||||
window.addEventListener(
|
||||
'message', self.onRequestUpdate_.bind(self, handler), false);
|
||||
} else {
|
||||
console.error('WrappedAuthenticatorPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback invoked when a response is received from the Authenticator.
|
||||
* @param function({data: Object}) callback
|
||||
* @param {Object} message message Object
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
|
||||
function(callback, message) {
|
||||
var messageObject = JSON.parse(message.data);
|
||||
var intentUrl = messageObject['intentURL'];
|
||||
|
||||
var errorCode = messageObject['errorCode'];
|
||||
var responseObject = null;
|
||||
if (messageObject.hasOwnProperty('data')) {
|
||||
responseObject = /** @type {Object} */ (
|
||||
JSON.parse(messageObject['data']));
|
||||
}
|
||||
|
||||
callback({'data': responseObject});
|
||||
};
|
||||
|
||||
/**
|
||||
* Base URL for intents to Authenticator.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
|
||||
'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
|
||||
|
||||
/**
|
||||
* Wrap the iOS client app with a MessagePort interface.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
u2f.WrappedIosPort_ = function() {};
|
||||
|
||||
/**
|
||||
* Launch the iOS client app request
|
||||
* @param {Object} message
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.postMessage = function(message) {
|
||||
var str = JSON.stringify(message);
|
||||
var url = "u2f://auth?" + encodeURI(str);
|
||||
location.replace(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells what type of port this is.
|
||||
* @return {String} port type
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.getPortType = function() {
|
||||
return "WrappedIosPort_";
|
||||
};
|
||||
|
||||
/**
|
||||
* Emulates the HTML 5 addEventListener interface.
|
||||
* @param {string} eventName
|
||||
* @param {function({data: Object})} handler
|
||||
*/
|
||||
u2f.WrappedIosPort_.prototype.addEventListener = function(eventName, handler) {
|
||||
var name = eventName.toLowerCase();
|
||||
if (name !== 'message') {
|
||||
console.error('WrappedIosPort only supports message');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets up an embedded trampoline iframe, sourced from the extension.
|
||||
* @param {function(MessagePort)} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getIframePort_ = function(callback) {
|
||||
// Create the iframe
|
||||
var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = iframeOrigin + '/u2f-comms.html';
|
||||
iframe.setAttribute('style', 'display:none');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
var channel = new MessageChannel();
|
||||
var ready = function(message) {
|
||||
if (message.data == 'ready') {
|
||||
channel.port1.removeEventListener('message', ready);
|
||||
callback(channel.port1);
|
||||
} else {
|
||||
console.error('First event on iframe port was not "ready"');
|
||||
}
|
||||
};
|
||||
channel.port1.addEventListener('message', ready);
|
||||
channel.port1.start();
|
||||
|
||||
iframe.addEventListener('load', function() {
|
||||
// Deliver the port to the iframe and initialize
|
||||
iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
//High-level JS API
|
||||
|
||||
/**
|
||||
* Default extension response timeout in seconds.
|
||||
* @const
|
||||
*/
|
||||
u2f.EXTENSION_TIMEOUT_SEC = 30;
|
||||
|
||||
/**
|
||||
* A singleton instance for a MessagePort to the extension.
|
||||
* @type {MessagePort|u2f.WrappedChromeRuntimePort_}
|
||||
* @private
|
||||
*/
|
||||
u2f.port_ = null;
|
||||
|
||||
/**
|
||||
* Callbacks waiting for a port
|
||||
* @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.waitingForPort_ = [];
|
||||
|
||||
/**
|
||||
* A counter for requestIds.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
u2f.reqCounter_ = 0;
|
||||
|
||||
/**
|
||||
* A map from requestIds to client callbacks
|
||||
* @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
|
||||
* |function((u2f.Error|u2f.SignResponse)))>}
|
||||
* @private
|
||||
*/
|
||||
u2f.callbackMap_ = {};
|
||||
|
||||
/**
|
||||
* Creates or retrieves the MessagePort singleton to use.
|
||||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||||
* @private
|
||||
*/
|
||||
u2f.getPortSingleton_ = function(callback) {
|
||||
if (u2f.port_) {
|
||||
callback(u2f.port_);
|
||||
} else {
|
||||
if (u2f.waitingForPort_.length == 0) {
|
||||
u2f.getMessagePort(function(port) {
|
||||
u2f.port_ = port;
|
||||
u2f.port_.addEventListener('message',
|
||||
/** @type {function(Event)} */ (u2f.responseHandler_));
|
||||
|
||||
// Careful, here be async callbacks. Maybe.
|
||||
while (u2f.waitingForPort_.length)
|
||||
u2f.waitingForPort_.shift()(u2f.port_);
|
||||
});
|
||||
}
|
||||
u2f.waitingForPort_.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles response messages from the extension.
|
||||
* @param {MessageEvent.<u2f.Response>} message
|
||||
* @private
|
||||
*/
|
||||
u2f.responseHandler_ = function(message) {
|
||||
var response = message.data;
|
||||
var reqId = response['requestId'];
|
||||
if (!reqId || !u2f.callbackMap_[reqId]) {
|
||||
console.error('Unknown or missing requestId in response.');
|
||||
return;
|
||||
}
|
||||
var cb = u2f.callbackMap_[reqId];
|
||||
delete u2f.callbackMap_[reqId];
|
||||
cb(response['responseData']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* If the JS API version supported by the extension is unknown, it first sends a
|
||||
* message to the extension to find out the supported API version and then it sends
|
||||
* the sign request.
|
||||
* @param {string=} appId
|
||||
* @param {string=} challenge
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sign = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
if (js_api_version === undefined) {
|
||||
// Send a message to get the extension to JS API version, then send the actual sign request.
|
||||
u2f.getApiVersion(
|
||||
function (response) {
|
||||
js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
|
||||
console.log("Extension JS API Version: ", js_api_version);
|
||||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||||
});
|
||||
} else {
|
||||
// We know the JS API version. Send the actual sign request in the supported API version.
|
||||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches an array of sign requests to available U2F tokens.
|
||||
* @param {string=} appId
|
||||
* @param {string=} challenge
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sendSignRequest = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* If the JS API version supported by the extension is unknown, it first sends a
|
||||
* message to the extension to find out the supported API version and then it sends
|
||||
* the register request.
|
||||
* @param {string=} appId
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.register = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
if (js_api_version === undefined) {
|
||||
// Send a message to get the extension to JS API version, then send the actual register request.
|
||||
u2f.getApiVersion(
|
||||
function (response) {
|
||||
js_api_version = response['js_api_version'] === undefined ? 0: response['js_api_version'];
|
||||
console.log("Extension JS API Version: ", js_api_version);
|
||||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||||
callback, opt_timeoutSeconds);
|
||||
});
|
||||
} else {
|
||||
// We know the JS API version. Send the actual register request in the supported API version.
|
||||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||||
callback, opt_timeoutSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches register requests to available U2F tokens. An array of sign
|
||||
* requests identifies already registered tokens.
|
||||
* @param {string=} appId
|
||||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.sendRegisterRequest = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||||
var req = u2f.formatRegisterRequest_(
|
||||
appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches a message to the extension to find out the supported
|
||||
* JS API version.
|
||||
* If the user is on a mobile phone and is thus using Google Authenticator instead
|
||||
* of the Chrome extension, don't send the request and simply return 0.
|
||||
* @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
|
||||
* @param {number=} opt_timeoutSeconds
|
||||
*/
|
||||
u2f.getApiVersion = function(callback, opt_timeoutSeconds) {
|
||||
u2f.getPortSingleton_(function(port) {
|
||||
// If we are using Android Google Authenticator or iOS client app,
|
||||
// do not fire an intent to ask which JS API version to use.
|
||||
if (port.getPortType) {
|
||||
var apiVersion;
|
||||
switch (port.getPortType()) {
|
||||
case 'WrappedIosPort_':
|
||||
case 'WrappedAuthenticatorPort_':
|
||||
apiVersion = 1.1;
|
||||
break;
|
||||
|
||||
default:
|
||||
apiVersion = 0;
|
||||
break;
|
||||
}
|
||||
callback({ 'js_api_version': apiVersion });
|
||||
return;
|
||||
}
|
||||
var reqId = ++u2f.reqCounter_;
|
||||
u2f.callbackMap_[reqId] = callback;
|
||||
var req = {
|
||||
type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
|
||||
timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
|
||||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
|
||||
requestId: reqId
|
||||
};
|
||||
port.postMessage(req);
|
||||
});
|
||||
};
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/* globals $, urls, updateEnabled */
|
||||
(function () {
|
||||
var origData;
|
||||
|
||||
var setupButtonClickOnRefreshedProperties = function () {
|
||||
$('#formRefreshCAS button').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Show the refreshModal
|
||||
var myModal = $('#refreshModal').modal({
|
||||
keyboard: false,
|
||||
backdrop: 'static'
|
||||
});
|
||||
|
||||
var primaryButton = myModal.find('.modal-footer button.btn-primary');
|
||||
|
||||
// Disable the primary button
|
||||
primaryButton.prop('disabled', true).text('Refreshing...');
|
||||
|
||||
$.post(e.target.parentNode.action, function (data) {
|
||||
if (data.length !== 0) {
|
||||
$('#refreshModal-label').text('Refreshed Properties');
|
||||
myModal.find('.modal-content .modal-body').html(
|
||||
'<pre>' + data + '</pre>' +
|
||||
'<p>Click "OK" to reload page.</p>'
|
||||
);
|
||||
} else {
|
||||
myModal.find('.modal-header .modal-title').text('Properties Refreshed');
|
||||
myModal.find('.modal-content .modal-body').html(
|
||||
'<p>Click "OK" to reload page.</p>'
|
||||
);
|
||||
}
|
||||
})
|
||||
.done(function () {
|
||||
primaryButton.prop('disabled', false).text('Reload page').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
window.location.reload();
|
||||
});
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
$('#refreshModal-label').text('Problem With Refreshing Properties');
|
||||
myModal.find('.modal-content .modal-body').html(
|
||||
'<div class="alert alert-warning"><strong>Status: ' + jqXHR.status + '</strong><p/>Unable to refresh the properties. Please try again.</div>'
|
||||
);
|
||||
primaryButton.prop('disabled', false).text('OK').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
myModal.modal('hide');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var createDataTable = function () {
|
||||
$('#viewConfigsTable').DataTable({
|
||||
'autoWidth': false,
|
||||
'initComplete': function (settings, json) {
|
||||
if (!json) {
|
||||
$('#loadingMessage').hide();
|
||||
$('#viewConfigError').show();
|
||||
$('#view-configuration').hide();
|
||||
} else {
|
||||
$('#loadingMessage').hide();
|
||||
$('#viewConfigError').hide();
|
||||
$('#view-configuration').show();
|
||||
}
|
||||
},
|
||||
'drawCallback': function () {
|
||||
var api = this.api();
|
||||
if (api.page.info().pages > 1) {
|
||||
$('#' + $.fn.dataTable.tables()[0].id + '_paginate')[0].style.display = 'block';
|
||||
} else {
|
||||
$('#' + $.fn.dataTable.tables()[0].id + '_paginate')[0].style.display = 'none';
|
||||
}
|
||||
|
||||
if (updateEnabled) {
|
||||
editTable();
|
||||
}
|
||||
},
|
||||
'processing': true,
|
||||
'ajax': {
|
||||
'url': urls.getConfiguration,
|
||||
'dataSrc': function (json) {
|
||||
var returnData = [];
|
||||
for (var item in json) {
|
||||
returnData.push({
|
||||
'key': '<code>' + item + '</code>',
|
||||
'value': '' + json[item] + ''
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
}
|
||||
},
|
||||
'columns': [
|
||||
{'data': 'key', 'className': 'col-xs-6 key'},
|
||||
{'data': 'value', 'className': 'col-xs-6 value'}
|
||||
],
|
||||
'pageLength': 50
|
||||
});
|
||||
};
|
||||
|
||||
var getRowData = function (row) {
|
||||
var tds = row.find('td');
|
||||
var tmp = {};
|
||||
$.each(tds, function (i) {
|
||||
if (i % 2 === 0) {
|
||||
tmp.key = $(this).text();
|
||||
} else {
|
||||
tmp.value = $(this).text();
|
||||
}
|
||||
});
|
||||
return tmp;
|
||||
};
|
||||
|
||||
var editTable = function () {
|
||||
$('#viewConfigsTable').editableTableWidget({editor: $('<textarea>')});
|
||||
|
||||
$('#viewConfigsTable td').on('focus', function () {
|
||||
origData = getRowData($(this).closest('tr'));
|
||||
});
|
||||
|
||||
$('#viewConfigsTable tr').on('change', function () {
|
||||
var newChanges = getRowData($(this));
|
||||
|
||||
var data = {old: origData, new: newChanges};
|
||||
$.ajax({url: urls.updateConfiguration, data: JSON.stringify(data), type: 'POST', contentType: 'application/json'})
|
||||
.fail(function () {
|
||||
var result = 'Failed to save settings.';
|
||||
$('#alertWrapper').addClass('alert-warning');
|
||||
$('#alertWrapper').removeClass('alert-success');
|
||||
|
||||
$('#alertWrapper').text(result);
|
||||
$('#alertWrapper').show();
|
||||
})
|
||||
.success(function () {
|
||||
var result = 'Saved settings successfully.';
|
||||
$('#alertWrapper').removeClass('alert-warning');
|
||||
$('#alertWrapper').addClass('alert-success');
|
||||
|
||||
$('#resultText').text(result);
|
||||
$('#alertWrapper').show();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// initialization *******
|
||||
(function init () {
|
||||
createDataTable();
|
||||
setupButtonClickOnRefreshedProperties();
|
||||
})();
|
||||
|
||||
// Public Methods
|
||||
return {
|
||||
/**
|
||||
* Not used
|
||||
*/
|
||||
};
|
||||
})();
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
$('.ui.search').search({
|
||||
type: 'message',
|
||||
searchDelay: 500,
|
||||
silent: true,
|
||||
apiSettings: {
|
||||
silent: true,
|
||||
cache: false,
|
||||
url: urls.search,
|
||||
onResponse: function (casResp) {
|
||||
var response = {
|
||||
results: {}
|
||||
};
|
||||
|
||||
for (var key in casResp) {
|
||||
if (casResp.hasOwnProperty(key)) {
|
||||
var prop = casResp[key];
|
||||
var group = prop.group;
|
||||
|
||||
if (response.results[group] === undefined) {
|
||||
response.results[group] = {
|
||||
name: group,
|
||||
results: []
|
||||
};
|
||||
}
|
||||
response.results[group].results.push({
|
||||
title: prop.id,
|
||||
description: prop.description,
|
||||
defaultValue: prop.defaultValue,
|
||||
type: prop.type,
|
||||
deprecated: prop.deprecated,
|
||||
requiredProperty: prop.requiredProperty,
|
||||
requiredModule: prop.requiredModule,
|
||||
requiredModuleAutomated: prop.requiredModuleAutomated
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
},
|
||||
},
|
||||
minCharacters: 3,
|
||||
templates: {
|
||||
message: function (response, type) {
|
||||
var html = '';
|
||||
$('#accordion').empty();
|
||||
|
||||
if (type === 'empty') {
|
||||
html += '<h3><i class=\'fa fa-search\' /> <strong>No Results</strong></h3>';
|
||||
html += '<div class=\'alert alert-warning\'>';
|
||||
html += '<i class=\'fa fa-exclamation-circle\'/> ';
|
||||
html += 'No search results could be found based on the provided query.';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
for (var group in response.results) {
|
||||
var modules = new Set();
|
||||
|
||||
html += '<h2><i class=\'fa fa-users\' /> <strong>Group: </strong>' + group + '</h2>';
|
||||
var props = response.results[group].results;
|
||||
|
||||
html += '<div>';
|
||||
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
html += '<p>';
|
||||
var prop = props[i];
|
||||
html += '<i class=\'fa fa-cogs\'/> ';
|
||||
html += 'Property: <code>' + prop.title + '=' + prop.defaultValue + '</code><br/>';
|
||||
if (prop.deprecated) {
|
||||
html += '<p/><div class=\'alert alert-warning\'>';
|
||||
html += '<i class=\'fa fa-exclamation-circle\'/> ';
|
||||
html += 'This property is deprecated and will be removed in future CAS versions.';
|
||||
html += '</div>';
|
||||
}
|
||||
if (prop.requiredProperty) {
|
||||
html += '<p/><div class=\'alert alert-success\'>';
|
||||
html += '<i class=\'fa fa-check-square\'/> ';
|
||||
html += 'This property is required.';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '<i class=\'fab fa-codepen\' /> Type: <code>' + prop.type + '</code><br/>';
|
||||
if (prop.description != null) {
|
||||
html += '<p>' + prop.description + '</p>';
|
||||
}
|
||||
|
||||
if (prop.requiredModule != null) {
|
||||
modules.add(prop.requiredModule);
|
||||
}
|
||||
html += '<hr>';
|
||||
}
|
||||
|
||||
if (modules.size > 0) {
|
||||
html += '<div>';
|
||||
html += '<p><i class=\'fa fa-gear\' /> Required Modules</p>';
|
||||
html += '<ul class=\'nav nav-pills\'>';
|
||||
html += '<li class=\'active\'><a href=\'#1\' data-toggle=\'tab\'>Maven</a></li>';
|
||||
html += '<li><a href=\'#2\' data-toggle=\'tab\'>Gradle</a></li>';
|
||||
html += '</ul>';
|
||||
|
||||
for (let moduleString of modules) {
|
||||
html += '<div class=\'tab-content\'>';
|
||||
|
||||
var moduleArr = moduleString.split('|');
|
||||
var module = moduleArr[0];
|
||||
|
||||
var maven = '<dependency>\n';
|
||||
maven += '\t<groupId>org.apereo.cas</groupId>\n';
|
||||
maven += '\t<artifactId>' + module + '</artifactId>\n';
|
||||
maven += '\t<cas.version>${cas.version}</cas.version>\n';
|
||||
maven += '</dependency>\n';
|
||||
html += '<div class=\'tab-pane active\' id=\'1\'><pre>' + maven + '</pre></div>';
|
||||
|
||||
var gradle = 'compile \'org.apereo.cas:' + module + ':${project.\'cas.version\'}\'\n';
|
||||
html += '<div class=\'tab-pane\' id=\'2\'><pre>' + gradle + '</pre></div>';
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
|
||||
$('#accordion').html(html);
|
||||
$('#accordion').accordion({
|
||||
heightStyle: 'content'
|
||||
});
|
||||
$('#accordion').accordion('refresh');
|
||||
return '';
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user