summaryrefslogtreecommitdiffstats
path: root/settings
diff options
context:
space:
mode:
authorRoeland Jago Douma <rullzer@users.noreply.github.com>2016-11-16 16:17:28 +0100
committerGitHub <noreply@github.com>2016-11-16 16:17:28 +0100
commit61453f5fd5eb3e742d1c757def36ce8f6be408f3 (patch)
tree6dfbb42c7d7f062234e54de6a19f333c97e5aece /settings
parent5f789fdebcd67ff7374becd9fd9cb28727a191de (diff)
parente633f2f8dff0ae99e7621b5c459474887c965c0e (diff)
downloadnextcloud-server-61453f5fd5eb3e742d1c757def36ce8f6be408f3.tar.gz
nextcloud-server-61453f5fd5eb3e742d1c757def36ce8f6be408f3.zip
Merge pull request #719 from nextcloud/lockdown
Allow restricting of app password permissions
Diffstat (limited to 'settings')
-rw-r--r--settings/Controller/AuthSettingsController.php20
-rw-r--r--settings/css/settings.css57
-rw-r--r--settings/js/authtoken_view.js53
3 files changed, 118 insertions, 12 deletions
diff --git a/settings/Controller/AuthSettingsController.php b/settings/Controller/AuthSettingsController.php
index 58994f0d59c..4e3d05a14e8 100644
--- a/settings/Controller/AuthSettingsController.php
+++ b/settings/Controller/AuthSettingsController.php
@@ -135,11 +135,13 @@ class AuthSettingsController extends Controller {
$token = $this->generateRandomDeviceToken();
$deviceToken = $this->tokenProvider->generateToken($token, $this->uid, $loginName, $password, $name, IToken::PERMANENT_TOKEN);
+ $tokenData = $deviceToken->jsonSerialize();
+ $tokenData['canDelete'] = true;
return [
'token' => $token,
'loginName' => $loginName,
- 'deviceToken' => $deviceToken
+ 'deviceToken' => $tokenData
];
}
@@ -180,4 +182,20 @@ class AuthSettingsController extends Controller {
return [];
}
+ /**
+ * @NoAdminRequired
+ * @NoSubadminRequired
+ *
+ * @param int $id
+ * @param array $scope
+ */
+ public function update($id, array $scope) {
+ $token = $this->tokenProvider->getTokenById($id);
+ $token->setScope([
+ 'filesystem' => $scope['filesystem'],
+ 'app' => array_values($scope['apps'])
+ ]);
+ $this->tokenProvider->updateToken($token);
+ return [];
+ }
}
diff --git a/settings/css/settings.css b/settings/css/settings.css
index 37197b9550c..9008ba5a985 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -149,6 +149,13 @@ table.nostyle td { padding: 0.2em 0; }
padding: 10px 10px 10px 0;
}
+#sessions .token-list td.more,
+#apppasswords .token-list td.more {
+ overflow: visible;
+ position: relative;
+ width: 16px;
+}
+
#sessions .token-list td,
#apppasswords .token-list td {
border-top: 1px solid #DDD;
@@ -156,18 +163,60 @@ table.nostyle td { padding: 0.2em 0; }
max-width: 200px;
white-space: nowrap;
overflow: hidden;
+ vertical-align: top;
+ position: relative;
}
-#sessions tr *:nth-child(2),
-#apppasswords tr *:nth-child(2) {
+#sessions tr>*:nth-child(2),
+#apppasswords tr>*:nth-child(2) {
text-align: right;
}
-#sessions .token-list td a.icon-delete,
-#apppasswords .token-list td a.icon-delete {
+#sessions .token-list td > a.icon,
+#apppasswords .token-list td > a.icon {
+ opacity: 0;
+ transition: opacity 0.5s;
+}
+
+#sessions .token-list a.icon,
+#apppasswords .token-list a.icon {
+ margin-top: 4px;
display: block;
+}
+
+#sessions .token-list tr:hover td > a.icon,
+#apppasswords .token-list tr:hover td > a.icon,
+#sessions .token-list tr.active td > a.icon,
+#apppasswords .token-list tr.active td > a.icon{
opacity: 0.6;
}
+#sessions .token-list td div.configure,
+#apppasswords .token-list td div.configure {
+ display: none;
+}
+
+#sessions .token-list tr.active div.configure,
+#apppasswords .token-list tr.active div.configure {
+ display: block;
+ position: absolute;
+ top: 45px;
+ right: -5px;
+ padding: 10px;
+}
+
+#sessions .token-list tr.active div.configure > *,
+#apppasswords .token-list tr.active div.configure > *{
+ margin-top: 5px;
+ margin-bottom: 5px;
+ display: inline-block;
+}
+
+#sessions .token-list tr.active a.icon-delete,
+#apppasswords .token-list tr.active a.icon-delete {
+ background-position: left;
+ padding-left: 20px;
+}
+
#new-app-login-name,
#new-app-password {
width: 186px;
diff --git a/settings/js/authtoken_view.js b/settings/js/authtoken_view.js
index 6eb04b63f20..20fe5235eb0 100644
--- a/settings/js/authtoken_view.js
+++ b/settings/js/authtoken_view.js
@@ -27,13 +27,22 @@
var TEMPLATE_TOKEN =
'<tr data-id="{{id}}">'
- + '<td class="has-tooltip" title="{{title}}"><span class="token-name">{{name}}</span></td>'
+ + '<td class="has-tooltip" title="{{title}}">'
+ + '<span class="token-name">{{name}}</span>'
+ + '</td>'
+ '<td><span class="last-activity has-tooltip" title="{{lastActivityTime}}">{{lastActivity}}</span></td>'
+ + '<td class="more">'
+ + '{{#if showMore}}<a class="icon icon-more"/>{{/if}}'
+ + '<div class="popovermenu bubble open menu configure">'
+ + '{{#if canScope}}'
+ + '<input class="filesystem checkbox" type="checkbox" id="{{id}}_filesystem" {{#if scope.filesystem}}checked{{/if}}/>'
+ + '<label for="{{id}}_filesystem">' + t('core', 'Allow filesystem access') + '</label><br/>'
+ + '{{/if}}'
+ '{{#if canDelete}}'
- + '<td><a class="icon-delete has-tooltip" title="' + t('core', 'Disconnect') + '"></a></td>'
- + '{{else}}'
- + '<td></td>'
+ + '<a class="icon icon-delete has-tooltip" title="' + t('core', 'Disconnect') + '">' + t('core', 'Revoke') +'</a>'
+ '{{/if}}'
+ + '</div>'
+ + '</td>'
+ '<tr>';
var SubView = OC.Backbone.View.extend({
@@ -70,7 +79,7 @@
var list = this.$('.token-list');
var tokens = this.collection.filter(function (token) {
- return parseInt(token.get('type'), 10) === _this.type;
+ return token.get('type') === _this.type;
});
list.html('');
@@ -78,7 +87,7 @@
this._toggleHeader(tokens.length > 0);
tokens.forEach(function (token) {
- var viewData = this._formatViewData(token.toJSON());
+ var viewData = this._formatViewData(token);
var html = _this.template(viewData);
var $html = $(html);
$html.find('.has-tooltip').tooltip({container: 'body'});
@@ -94,10 +103,13 @@
this.$('.hidden-when-empty').toggleClass('hidden', !show);
},
- _formatViewData: function (viewData) {
+ _formatViewData: function (token) {
+ var viewData = token.toJSON();
var ts = viewData.lastActivity * 1000;
viewData.lastActivity = OC.Util.relativeModifiedDate(ts);
viewData.lastActivityTime = OC.Util.formatDate(ts, 'LLL');
+ viewData.canScope = token.get('type') === 1;
+ viewData.showMore = viewData.canScope || viewData.canDelete;
// preserve title for cases where we format it further
viewData.title = viewData.name;
@@ -204,6 +216,8 @@
var $el = $(el);
$el.on('click', 'a.icon-delete', _.bind(_this._onDeleteToken, _this));
+ $el.on('click', '.icon-more', _.bind(_this._onConfigureToken, _this));
+ $el.on('change', 'input.filesystem', _.bind(_this._onSetTokenScope, _this));
});
this._form = $('#app-password-form');
@@ -325,6 +339,13 @@
this._addAppPasswordBtn.toggleClass('icon-loading-small', state);
},
+ _onConfigureToken: function (event) {
+ var $target = $(event.target);
+ var $row = $target.closest('tr');
+ $row.toggleClass('active');
+ var id = $row.data('id');
+ },
+
_onDeleteToken: function (event) {
var $target = $(event.target);
var $row = $target.closest('tr');
@@ -353,6 +374,24 @@
});
},
+ _onSetTokenScope: function (event) {
+ var $target = $(event.target);
+ var $row = $target.closest('tr');
+ var id = $row.data('id');
+
+ var token = this.collection.get(id);
+ if (_.isUndefined(token)) {
+ // Ignore event
+ return;
+ }
+
+ var scope = token.get('scope');
+ scope.filesystem = $target.is(":checked");
+
+ token.set('scope', scope);
+ token.save();
+ },
+
_toggleFormResult: function (showForm) {
if (showForm) {
this._result.slideUp();