/*******************************************************************************
* Copyright 2017 The MITRE Corporation
* and the MIT Internet Trust Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
var AccessTokenModel = Backbone.Model.extend({
idAttribute: 'id',
defaults:{
id:null,
value:null,
refreshTokenId:null,
scopes:[],
clientId:null,
userId:null,
expiration:null
},
urlRoot: 'api/tokens/access'
});
var AccessTokenCollection = Backbone.Collection.extend({
idAttribute: 'id',
model: AccessTokenModel,
url: 'api/tokens/access'
});
var AccessTokenView = Backbone.View.extend({
tagName: 'tr',
initialize:function (options) {
this.options = options;
if (!this.template) {
this.template = _.template($('#tmpl-access-token').html());
}
if (!this.scopeTemplate) {
this.scopeTemplate = _.template($('#tmpl-scope-list').html());
}
if (!this.moreInfoTemplate) {
this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html());
}
this.model.bind('change', this.render, this);
},
events: {
'click .btn-delete':'deleteToken',
'click .token-substring':'showTokenValue',
'click .toggleMoreInformation': 'toggleMoreInformation'
},
render:function (eventName) {
var expirationDate = this.model.get("expiration");
if (expirationDate == null) {
expirationDate = "Never";
} else if (!moment(expirationDate).isValid()) {
expirationDate = "Unknown";
} else {
expirationDate = moment(expirationDate).calendar();
}
var json = {token: this.model.toJSON(), client: this.options.client.toJSON(), formattedExpiration: expirationDate};
this.$el.html(this.template(json));
// hide full value
$('.token-full', this.el).hide();
// show scopes
$('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('scopes'), systemScopes: this.options.systemScopeList}));
$('.client-more-info-block', this.el).html(this.moreInfoTemplate({client: this.options.client.toJSON()}));
$(this.el).i18n();
return this;
},
deleteToken:function (e) {
e.preventDefault();
if (confirm($.t("token.token-table.confirm"))) {
var _self = this;
this.model.destroy({
dataType: false, processData: false,
success:function () {
_self.$el.fadeTo("fast", 0.00, function () { //fade
$(this).slideUp("fast", function () { //slide up
$(this).remove(); //then remove from the DOM
// refresh the table in case we removed an id token, too
_self.parentView.refreshTable();
});
});
},
error:app.errorHandlerView.handleError()
});
this.parentView.delegateEvents();
}
return false;
},
toggleMoreInformation:function(e) {
e.preventDefault();
if ($('.moreInformation', this.el).is(':visible')) {
// hide it
$('.moreInformation', this.el).hide('fast');
$('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-right');
$('.moreInformationContainer', this.el).removeClass('alert').removeClass('alert-info').addClass('muted');
} else {
// show it
$('.moreInformation', this.el).show('fast');
$('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-down');
$('.moreInformationContainer', this.el).addClass('alert').addClass('alert-info').removeClass('muted');
}
},
close:function () {
$(this.el).unbind();
$(this.el).empty();
},
showTokenValue:function (e) {
e.preventDefault();
$('.token-substring', this.el).hide();
$('.token-full', this.el).show();
}
});
var RefreshTokenModel = Backbone.Model.extend({
idAttribute: 'id',
defaults:{
id:null,
value:null,
scopes:[],
clientId:null,
userId:null,
expiration:null
},
urlRoot: 'api/tokens/refresh'
});
var RefreshTokenCollection = Backbone.Collection.extend({
idAttribute: 'id',
model: RefreshTokenModel,
url: 'api/tokens/refresh'
});
var RefreshTokenView = Backbone.View.extend({
tagName: 'tr',
initialize:function (options) {
this.options = options;
if (!this.template) {
this.template = _.template($('#tmpl-refresh-token').html());
}
if (!this.scopeTemplate) {
this.scopeTemplate = _.template($('#tmpl-scope-list').html());
}
if (!this.moreInfoTemplate) {
this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html());
}
this.model.bind('change', this.render, this);
},
events: {
'click .btn-delete':'deleteToken',
'click .token-substring':'showTokenValue',
'click .toggleMoreInformation': 'toggleMoreInformation'
},
render:function (eventName) {
var expirationDate = this.model.get("expiration");
if (expirationDate == null) {
expirationDate = "Never";
} else if (!moment(expirationDate).isValid()) {
expirationDate = "Unknown";
} else {
expirationDate = moment(expirationDate).calendar();
}
var json = {token: this.model.toJSON(), client: this.options.client.toJSON(), formattedExpiration: expirationDate, accessTokenCount: this.options.accessTokenCount};
this.$el.html(this.template(json));
// hide full value
$('.token-full', this.el).hide();
// show scopes
$('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('scopes'), systemScopes: this.options.systemScopeList}));
$('.client-more-info-block', this.el).html(this.moreInfoTemplate({client: this.options.client.toJSON()}));
$(this.el).i18n();
return this;
},
deleteToken:function (e) {
e.preventDefault();
if (confirm($.t('token.token-table.confirm-refresh'))) {
var _self = this;
this.model.destroy({
dataType: false, processData: false,
success:function () {
_self.$el.fadeTo("fast", 0.00, function () { //fade
$(this).slideUp("fast", function () { //slide up
$(this).remove(); //then remove from the DOM
// refresh the table in case the access tokens have changed, too
_self.parentView.refreshTable();
});
});
},
error:app.errorHandlerView.handleError()
});
_self.parentView.delegateEvents();
}
return false;
},
toggleMoreInformation:function(e) {
e.preventDefault();
if ($('.moreInformation', this.el).is(':visible')) {
// hide it
$('.moreInformation', this.el).hide('fast');
$('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-right');
$('.moreInformationContainer', this.el).removeClass('alert').removeClass('alert-info').addClass('muted');
} else {
// show it
$('.moreInformation', this.el).show('fast');
$('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-down');
$('.moreInformationContainer', this.el).addClass('alert').addClass('alert-info').removeClass('muted');
}
},
close:function () {
$(this.el).unbind();
$(this.el).empty();
},
showTokenValue:function (e) {
e.preventDefault();
$('.token-substring', this.el).hide();
$('.token-full', this.el).show();
}
});
var TokenListView = Backbone.View.extend({
tagName: 'span',
initialize:function(options) {
this.options = options;
},
events:{
"click .refresh-table":"refreshTable",
'page .paginator-access':'changePageAccess',
'page .paginator-refresh':'changePageRefresh'
},
load:function(callback) {
if (this.model.access.isFetched &&
this.model.refresh.isFetched &&
this.options.clientList.isFetched &&
this.options.systemScopeList.isFetched) {
callback();
return;
}
$('#loadingbox').sheet('show');
$('#loading').html(
'' + $.t('token.token-table.access-tokens') + ' ' +
'' + $.t('token.token-table.refresh-tokens') + ' ' +
'' + $.t('common.clients') + ' ' +
'' + $.t('common.scopes') + ' '
);
$.when(this.model.access.fetchIfNeeded({success:function(e) {$('#loading-access').addClass('label-success');}, error: app.errorHandlerView.handleError()}),
this.model.refresh.fetchIfNeeded({success:function(e) {$('#loading-refresh').addClass('label-success');}, error: app.errorHandlerView.handleError()}),
this.options.clientList.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}, error: app.errorHandlerView.handleError()}),
this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error: app.errorHandlerView.handleError()}))
.done(function() {
$('#loadingbox').sheet('hide');
callback();
});
},
changePageAccess:function(event, num) {
$('.paginator-access', this.el).bootpag({page: num});
$('#access-token-table tbody tr', this.el).each(function(index, element) {
if (Math.ceil((index + 1) / 10) != num) {
$(element).hide();
} else {
$(element).show();
}
});
},
changePageRefresh:function(event, num) {
$('.paginator-refresh', this.el).bootpag({page: num});
$('#refresh-token-table tbody tr', this.el).each(function(index, element) {
if (Math.ceil((index + 1) / 10) != num) {
$(element).hide();
} else {
$(element).show();
}
});
},
refreshTable:function(e) {
$('#loadingbox').sheet('show');
$('#loading').html(
'' + $.t('token.token-table.access-tokens') + ' ' +
'' + $.t('token.token-table.refresh-tokens') + ' ' +
'' + $.t('common.clients') + ' ' +
'' + $.t('common.scopes') + ' '
);
var _self = this;
$.when(this.model.access.fetch({success:function(e) {$('#loading-access').addClass('label-success');}, error: app.errorHandlerView.handleError()}),
this.model.refresh.fetch({success:function(e) {$('#loading-refresh').addClass('label-success');}, error: app.errorHandlerView.handleError()}),
this.options.clientList.fetch({success:function(e) {$('#loading-clients').addClass('label-success');}, error: app.errorHandlerView.handleError()}),
this.options.systemScopeList.fetch({success:function(e) {$('#loading-scopes').addClass('label-success');}, error: app.errorHandlerView.handleError()}))
.done(function(){
_self.render();
$('#loadingbox').sheet('hide');
});
},
togglePlaceholder:function() {
if (this.model.access.length > 0) {
$('#access-token-table', this.el).show();
$('#access-token-table-empty', this.el).hide();
} else {
$('#access-token-table', this.el).hide();
$('#access-token-table-empty', this.el).show();
}
if (this.model.refresh.length > 0) {
$('#refresh-token-table', this.el).show();
$('#refresh-token-table-empty', this.el).hide();
} else {
$('#refresh-token-table', this.el).hide();
$('#refresh-token-table-empty', this.el).show();
}
$('#access-token-count', this.el).html(this.model.access.length);
$('#refresh-token-count', this.el).html(this.model.refresh.length);
},
render: function (eventName) {
// append and render the table structure
$(this.el).html($('#tmpl-token-table').html());
var _self = this;
// set up pagination
var numPagesAccess = Math.ceil(this.model.access.length / 10);
if (numPagesAccess > 1) {
$('.paginator-access', this.el).show();
$('.paginator-access', this.el).bootpag({
total: numPagesAccess,
page: 1
});
} else {
$('.paginator-access', this.el).hide();
}
// count up refresh tokens
var refreshCount = {};
_.each(this.model.access.models, function (token, index) {
// look up client
var client = _self.options.clientList.getByClientId(token.get('clientId'));
var view = new AccessTokenView({model: token, client: client, systemScopeList: _self.options.systemScopeList});
view.parentView = _self;
var element = view.render().el;
$('#access-token-table', _self.el).append(element);
if (Math.ceil((index + 1) / 10) != 1) {
$(element).hide();
}
//console.log(token.get('refreshTokenId'));
var refId = token.get('refreshTokenId');
if (refId != null) {
if (refreshCount[refId]) {
refreshCount[refId] += 1;
} else {
refreshCount[refId] = 1;
}
}
});
//console.log(refreshCount);
// set up pagination
var numPagesRefresh = Math.ceil(this.model.refresh.length / 10);
if (numPagesRefresh > 1) {
$('.paginator-refresh', this.el).show();
$('.paginator-refresh', this.el).bootpag({
total: numPagesRefresh,
page: 1
});
} else {
$('.paginator-refresh', this.el).hide();
}
_.each(this.model.refresh.models, function (token, index) {
// look up client
var client = _self.options.clientList.getByClientId(token.get('clientId'));
var view = new RefreshTokenView({model: token, client: client, systemScopeList: _self.options.systemScopeList, accessTokenCount: refreshCount[token.get('id')]});
view.parentView = _self;
var element = view.render().el;
$('#refresh-token-table', _self.el).append(element);
if (Math.ceil((index + 1) / 10) != 1) {
$(element).hide();
}
});
/*
_.each(this.model.models, function (scope) {
$("#scope-table", this.el).append(new SystemScopeView({model: scope}).render().el);
}, this);
*/
this.togglePlaceholder();
$(this.el).i18n();
return this;
}
});
ui.routes.push({path: "user/tokens", name: "tokens", callback:
function() {
this.breadCrumbView.collection.reset();
this.breadCrumbView.collection.add([
{text:$.t('admin.home'), href:""},
{text:$.t('token.manage'), href:"manage/#user/tokens"}
]);
this.updateSidebar('user/tokens');
var view = new TokenListView({model: {access: this.accessTokensList, refresh: this.refreshTokensList}, clientList: this.clientList, systemScopeList: this.systemScopeList});
view.load(
function(collection, response, options) {
$('#content').html(view.render().el);
setPageTitle($.t('token.manage'));
}
);
}
});
ui.templates.push('resources/template/token.html');