move tokens entirely into token page

This commit is contained in:
Girish Ramakrishnan
2019-11-07 14:41:28 -08:00
parent 0c5930d5cf
commit 97782d29cc
4 changed files with 146 additions and 213 deletions
-76
View File
@@ -193,49 +193,6 @@
</div>
</div>
<!-- Modal add token -->
<div class="modal fade" id="tokenAddModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Create API token</h4>
</div>
<div class="modal-body">
<div ng-hide="tokenAdd.token.accessToken">
<form name="tokenAddForm" role="form" novalidate ng-submit="tokenAdd.submit(apiClient)" autocomplete="off">
<div class="form-group" ng-class="{ 'has-error': (tokenAddForm.tokenName.$dirty && tokenAddForm.tokenName.$invalid) || (!tokenAddForm.tokenName.$dirty && tokenAdd.error.tokenName)}">
<label class="control-label">Token name</label>
<div class="control-label" ng-show="(!tokenAddForm.tokenName.$dirty && tokenAdd.error.tokenName) || (tokenAddForm.tokenName.$dirty && tokenAddForm.tokenName.$invalid)">
<small ng-show="tokenAddForm.tokenName.$error.required">A token name is required</small>
<small ng-show="(tokenAddForm.tokenName.$dirty && tokenAddForm.tokenName.$invalid) && !tokenAddForm.tokenName.$error.required">This token name is not valid</small>
<small ng-show="!tokenAddForm.email.$dirty && tokenAdd.error.tokenName">{{ tokenAdd.error.tokenName }}</small>
</div>
<input type="text" class="form-control" ng-model="tokenAdd.tokenName" id="inputTokenAddName" name="tokenName" required autofocus>
</div>
<input class="ng-hide" type="submit" ng-disabled="tokenAddForm.$invalid"/>
</form>
</div>
<div ng-show="tokenAdd.token.accessToken">
Use the following token to authenticate against the <a href="https://cloudron.io/developer/api/" target="_blank">Cloudron API</a>:
<br/>
<b ng-click-select>{{ tokenAdd.token.accessToken }}</b>
<br/>
<br/>
<p>Please copy the token now. It won't be shown again for security purposes.</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-success" ng-click="tokenAdd.submit(apiClient)" ng-hide="tokenAdd.token.accessToken" ng-disabled="tokenAddForm.$invalid || tokenAdd.busy">
<i class="fa fa-circle-notch fa-spin" ng-show="tokenAdd.busy"></i> Generate Token
</button>
</div>
</div>
</div>
</div>
<div class="content">
<div class="text-left">
@@ -302,37 +259,4 @@
</div>
</div>
</div>
<div class="text-left" ng-show="user.admin && showApiTokens">
<h3>API Tokens <button class="btn btn-primary btn-sm pull-right" ng-click="tokenAdd.show(apiClient)"><i class="fa fa-plus"></i> New Token</button></h3>
</div>
<!-- we will always at least have the webadmin token here, so activeClients always will have one entry with at least one token -->
<div class="card" ng-show="user.admin && showApiTokens">
<div class="grid-item-top">
<div class="row">
<div class="col-xs-12">
<p>These tokens can be used to access the <a ng-href="{{ config.webServerOrigin + '/developer/api/' }}" target="_blank">Cloudron API</a>.</p>
<table class="table table-hover">
<thead>
<tr>
<th style="width:70%">Name</th>
<th style="width: 5%" class="text-right">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="token in apiClient.activeTokens">
<td class="text-left elide-table-cell">
{{ token.name || '-' }}
</td>
<td class="text-right no-wrap" style="vertical-align: bottom">
<button class="btn btn-xs btn-danger pull-right" ng-click="removeToken(apiClient, token)" title="Revoke Token"><i class="far fa-trash-alt"></i></button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
+1 -57
View File
@@ -12,7 +12,6 @@ angular.module('Application').controller('ProfileController', ['$scope', '$locat
$scope.webadminClient = {};
$scope.apiClient = {};
$scope.cliClient = {};
$scope.showApiTokens = !!$location.search().tokens;
$scope.twoFactorAuthentication = {
busy: false,
@@ -298,61 +297,6 @@ angular.module('Application').controller('ProfileController', ['$scope', '$locat
}
};
$scope.tokenAdd = {
token: {},
tokenName: '',
busy: false,
error: {},
reset: function () {
$scope.tokenAdd.busy = false;
$scope.tokenAdd.token = {};
$scope.tokenAdd.error.tokenName = null;
$scope.tokenAdd.tokenName = '';
$scope.tokenAddForm.$setUntouched();
$scope.tokenAddForm.$setPristine();
},
show: function () {
$scope.tokenAdd.reset();
$('#tokenAddModal').modal('show');
},
submit: function (client) {
$scope.tokenAdd.busy = true;
$scope.tokenAdd.token = {};
var expiresAt = Date.now() + 100 * 365 * 24 * 60 * 60 * 1000; // ~100 years from now
Client.createTokenByClientId(client.id, '*' /* scope */, expiresAt, $scope.tokenAdd.tokenName, function (error, result) {
if (error) {
if (error.statusCode === 400) {
$scope.tokenAdd.error.tokenName = 'Invalid token name';
$scope.tokenAddForm.tokenName.$setPristine();
$('#inputTokenAddName').focus();
} else {
console.error('Unable to create token.', error);
}
return;
}
$scope.tokenAdd.busy = false;
$scope.tokenAdd.token = result;
refreshClientTokens(client);
});
}
};
$scope.removeToken = function (client, token) {
Client.delToken(client.id, token.id, function (error) {
if (error) console.error(error);
refreshClientTokens(client);
});
};
function revokeTokensByClient(client, callback) {
Client.delTokensByClientId(client.id, function (error) {
if (error) console.error(error);
@@ -399,7 +343,7 @@ angular.module('Application').controller('ProfileController', ['$scope', '$locat
});
// setup all the dialog focus handling
['passwordChangeModal', 'emailChangeModal', 'fallbackEmailChangeModal', 'displayNameChangeModal', 'twoFactorAuthenticationEnableModal', 'twoFactorAuthenticationDisableModal', 'tokenAddModal'].forEach(function (id) {
['passwordChangeModal', 'emailChangeModal', 'fallbackEmailChangeModal', 'displayNameChangeModal', 'twoFactorAuthenticationEnableModal', 'twoFactorAuthenticationDisableModal'].forEach(function (id) {
$('#' + id).on('shown.bs.modal', function () {
$(this).find("[autofocus]:first").focus();
});
+110 -70
View File
@@ -68,90 +68,130 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">New token created</h4>
<h4 class="modal-title">Create API token</h4>
</div>
<div class="modal-body">
<div ng-hide="tokenAdd.token.accessToken">
<form name="tokenAddForm" role="form" novalidate ng-submit="tokenAdd.submit(apiClient)" autocomplete="off">
<div class="form-group" ng-class="{ 'has-error': (tokenAddForm.tokenName.$dirty && tokenAddForm.tokenName.$invalid) || (!tokenAddForm.tokenName.$dirty && tokenAdd.error.tokenName)}">
<label class="control-label">Token name</label>
<div class="control-label" ng-show="(!tokenAddForm.tokenName.$dirty && tokenAdd.error.tokenName) || (tokenAddForm.tokenName.$dirty && tokenAddForm.tokenName.$invalid)">
<small ng-show="tokenAddForm.tokenName.$error.required">A token name is required</small>
<small ng-show="(tokenAddForm.tokenName.$dirty && tokenAddForm.tokenName.$invalid) && !tokenAddForm.tokenName.$error.required">This token name is not valid</small>
<small ng-show="!tokenAddForm.email.$dirty && tokenAdd.error.tokenName">{{ tokenAdd.error.tokenName }}</small>
</div>
<input type="text" class="form-control" ng-model="tokenAdd.tokenName" id="inputTokenAddName" name="tokenName" required autofocus>
</div>
<input class="ng-hide" type="submit" ng-disabled="tokenAddForm.$invalid"/>
</form>
</div>
<div ng-show="tokenAdd.token.accessToken">
Use the following token to authenticate against the <a href="https://cloudron.io/developer/api/" target="_blank">Cloudron API</a>:
<br/>
<b ng-click-select>{{ tokenAdd.token.accessToken }}</b>
<br/>
<br/>
<p>Please copy the token now. It won't be shown again for security purposes.</p>
</div>
</div>
<div class="modal-body"><b ng-click-select>{{ tokenAdd.token.accessToken }}</b></div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Done</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-success" ng-click="tokenAdd.submit(apiClient)" ng-hide="tokenAdd.token.accessToken" ng-disabled="tokenAddForm.$invalid || tokenAdd.busy">
<i class="fa fa-circle-notch fa-spin" ng-show="tokenAdd.busy"></i> Generate Token
</button>
</div>
</div>
</div>
</div>
<div class="content">
<div class="text-left">
<h3>Access Tokens <button class="btn btn-xs btn-primary btn-outline pull-right" ng-click="tokenAdd.show(apiClient)"><i class="fa fa-plus"></i> New Token</button> </h3>
</div>
<div class="text-left">
<h3>API Tokens <button class="btn btn-primary btn-sm pull-right" ng-click="tokenAdd.show(apiClient)"><i class="fa fa-plus"></i> New Token</button></h3>
</div>
<!-- we will always at least have the webadmin token here, so activeClients always will have one entry with at least one token -->
<div class="card">
<div class="grid-item-top">
<div class="row">
<div class="col-xs-12">
<p>These tokens can be used to access the <a ng-href="{{ config.webServerOrigin + '/developer/api/' }}" target="_blank">Cloudron API</a>.</p>
<br/>
<h4 class="text-muted">Active Tokens</h4>
<hr/>
<p ng-repeat="token in apiClient.activeTokens">
<span ng-click-select>{{ token.accessToken }}</span> <button class="btn btn-xs btn-danger pull-right" ng-click="removeToken(apiClient, token)" title="Revoke Token"><i class="far fa-trash-alt"></i></button>
</p>
</div>
</div>
</div>
</div>
<!-- we will always at least have the webadmin token here, so activeClients always will have one entry with at least one token -->
<div class="card">
<div class="grid-item-top">
<div class="row">
<div class="col-xs-12">
<p>These tokens can be used to access the <a ng-href="{{ config.webServerOrigin + '/developer/api/' }}" target="_blank">Cloudron API</a>.</p>
<table class="table table-hover">
<thead>
<tr>
<th style="width:70%">Name</th>
<th style="width: 5%" class="text-right">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="token in apiClient.activeTokens">
<td class="text-left elide-table-cell">
{{ token.name || '-' }}
</td>
<td class="text-right no-wrap" style="vertical-align: bottom">
<button class="btn btn-xs btn-danger pull-right" ng-click="removeToken(apiClient, token)" title="Revoke Token"><i class="far fa-trash-alt"></i></button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<br/>
<br/>
<div class="text-left">
<h3>OAuth Apps<button class="btn btn-xs btn-primary btn-outline pull-right" ng-click="clientAdd.show()"><i class="fa fa-plus"></i> New OAuth Client</button></h3>
</div>
<div class="text-left">
<h3>OAuth Apps<button class="btn btn-xs btn-primary btn-outline pull-right" ng-click="clientAdd.show()"><i class="fa fa-plus"></i> New OAuth Client</button></h3>
</div>
<!-- we will always at least have the webadmin token here, so activeClients always will have one entry with at least one token -->
<div class="card" ng-repeat="client in activeClients | activeOAuthClients:user">
<div class="grid-item-top">
<div class="row">
<div class="col-xs-12">
<h4 class="text-muted">
{{client.name}} <span ng-show="client.type !== 'external' && client.type !== 'built-in'">on {{client.domain}}</span>
</h4>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="row">
<div class="col-xs-12">
<b>{{ client.activeTokens.length }}</b> active token(s).
<br/>
<a href="" data-toggle="collapse" data-parent="#accordion" data-target="#collapse{{client.id}}">Advanced</a>
<div id="collapse{{client.id}}" class="panel-collapse collapse">
<div class="panel-body">
<h4 class="text-muted">Credentials <button class="btn btn-xs btn-danger pull-right" ng-click="clientRemove.show(client)" title="Remove OAuth Client" ng-show="client.type === 'external'">Remove OAuth Client</button></h4>
<hr/>
<p>Scope: <b ng-click-select>{{ client.scope }}</b></p>
<p>RedirectURI: <b ng-click-select>{{ client.redirectURI }}</b></p>
<p>Client ID: <b ng-click-select>{{ client.id }}</b></p>
<p ng-show="client.clientSecret" style="overflow: auto; white-space: nowrap;">Client Secret: <b ng-click-select>{{ client.clientSecret }}</b></p>
<!-- we will always at least have the webadmin token here, so activeClients always will have one entry with at least one token -->
<div class="card" ng-repeat="client in activeClients | activeOAuthClients:user">
<div class="grid-item-top">
<div class="row">
<div class="col-xs-12">
<h4 class="text-muted">
{{client.name}} <span ng-show="client.type !== 'external' && client.type !== 'built-in'">on {{client.domain}}</span>
</h4>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="row">
<div class="col-xs-12">
<b>{{ client.activeTokens.length }}</b> active token(s).
<br/>
<a href="" data-toggle="collapse" data-parent="#accordion" data-target="#collapse{{client.id}}">Advanced</a>
<div id="collapse{{client.id}}" class="panel-collapse collapse">
<div class="panel-body">
<h4 class="text-muted">Credentials <button class="btn btn-xs btn-danger pull-right" ng-click="clientRemove.show(client)" title="Remove OAuth Client" ng-show="client.type === 'external'">Remove OAuth Client</button></h4>
<hr/>
<p>Scope: <b ng-click-select>{{ client.scope }}</b></p>
<p>RedirectURI: <b ng-click-select>{{ client.redirectURI }}</b></p>
<p>Client ID: <b ng-click-select>{{ client.id }}</b></p>
<p ng-show="client.clientSecret" style="overflow: auto; white-space: nowrap;">Client Secret: <b ng-click-select>{{ client.clientSecret }}</b></p>
<br/>
<br/>
<h4 class="text-muted">Tokens
<div class="pull-right">
<button class="btn btn-xs btn-default" ng-click="removeAccessTokens(client)" ng-disabled="!client.activeTokens.length || client.busy"><i class="fa fa-circle-notch fa-spin" ng-show="client.busy"></i> Revoke All</button>
<button class="btn btn-xs btn-primary btn-outline" ng-click="tokenAdd.show(client)"><i class="fa fa-plus"></i> New Token</button>
</div>
</h4>
<h4 class="text-muted">Tokens
<div class="pull-right">
<button class="btn btn-xs btn-default" ng-click="removeAccessTokens(client)" ng-disabled="!client.activeTokens.length || client.busy"><i class="fa fa-circle-notch fa-spin" ng-show="client.busy"></i> Revoke All</button>
<button class="btn btn-xs btn-primary btn-outline" ng-click="tokenAdd.show(client)"><i class="fa fa-plus"></i> New Token</button>
</div>
</h4>
<hr/>
<hr/>
<p ng-repeat="token in client.activeTokens">
<b ng-click-select>{{ token.accessToken }}</b> <button class="btn btn-xs btn-danger pull-right" ng-click="removeToken(client, token)" title="Revoke Token"><i class="far fa-trash-alt"></i></button>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<p ng-repeat="token in client.activeTokens">
<b ng-click-select>{{ token.accessToken }}</b> <button class="btn btn-xs btn-danger pull-right" ng-click="removeToken(client, token)" title="Revoke Token"><i class="far fa-trash-alt"></i></button>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
+35 -10
View File
@@ -94,31 +94,56 @@ angular.module('Application').controller('TokensController', ['$scope', '$locati
}
};
$scope.tokenAdd = {
busy: false,
token: {},
show: function (client) {
$scope.tokenAdd = {
token: {},
tokenName: '',
busy: false,
error: {},
reset: function () {
$scope.tokenAdd.busy = false;
$scope.tokenAdd.token = {};
$scope.tokenAdd.error.tokenName = null;
$scope.tokenAdd.tokenName = '';
$scope.tokenAddForm.$setUntouched();
$scope.tokenAddForm.$setPristine();
},
show: function () {
$scope.tokenAdd.reset();
$('#tokenAddModal').modal('show');
},
submit: function (client) {
$scope.tokenAdd.busy = true;
$scope.tokenAdd.token = {};
var expiresAt = Date.now() + 100 * 365 * 24 * 60 * 60 * 1000; // ~100 years from now
Client.createTokenByClientId(client.id, '*' /* scope */, expiresAt, '' /* name */, function (error, result) {
if (error) return console.error(error);
Client.createTokenByClientId(client.id, '*' /* scope */, expiresAt, $scope.tokenAdd.tokenName, function (error, result) {
if (error) {
if (error.statusCode === 400) {
$scope.tokenAdd.error.tokenName = 'Invalid token name';
$scope.tokenAddForm.tokenName.$setPristine();
$('#inputTokenAddName').focus();
} else {
console.error('Unable to create token.', error);
}
return;
}
$scope.tokenAdd.busy = false;
$scope.tokenAdd.token = result;
$('#tokenAddModal').modal('show');
refreshClientTokens(client);
});
}
};
$scope.removeToken = function (client, token) {
Client.delToken(client.id, token.accessToken, function (error) {
Client.delToken(client.id, token.id, function (error) {
if (error) console.error(error);
refreshClientTokens(client);
@@ -159,7 +184,7 @@ angular.module('Application').controller('TokensController', ['$scope', '$locati
Client.onReady(refresh);
// setup all the dialog focus handling
['clientAddModal'].forEach(function (id) {
['clientAddModal', 'tokenAddModal'].forEach(function (id) {
$('#' + id).on('shown.bs.modal', function () {
$(this).find("[autofocus]:first").focus();
});