diff options
author | Christoph Wurst <christoph@owncloud.com> | 2016-05-18 18:25:05 +0200 |
---|---|---|
committer | Christoph Wurst <christoph@owncloud.com> | 2016-05-23 09:11:12 +0200 |
commit | 6495534bcdbbda8aa2748cc9f5d94dcb2bc7a04a (patch) | |
tree | b000c3f7bc3b5dc2cc96b80b7f9ece2c51e9ba01 /settings | |
parent | 12431aa3997154aaea4eec11c2dd65f9e5dbe179 (diff) | |
download | nextcloud-server-6495534bcdbbda8aa2748cc9f5d94dcb2bc7a04a.tar.gz nextcloud-server-6495534bcdbbda8aa2748cc9f5d94dcb2bc7a04a.zip |
add button to add new device tokens
Diffstat (limited to 'settings')
-rw-r--r-- | settings/Application.php | 2 | ||||
-rw-r--r-- | settings/Controller/AuthSettingsController.php | 71 | ||||
-rw-r--r-- | settings/css/settings.css | 22 | ||||
-rw-r--r-- | settings/js/authtoken_view.js | 95 | ||||
-rw-r--r-- | settings/templates/personal.php | 11 |
5 files changed, 179 insertions, 22 deletions
diff --git a/settings/Application.php b/settings/Application.php index 7069fc9c35d..728c2bf9de4 100644 --- a/settings/Application.php +++ b/settings/Application.php @@ -104,6 +104,8 @@ class Application extends App { $c->query('Request'), $c->query('ServerContainer')->query('OC\Authentication\Token\IProvider'), $c->query('UserManager'), + $c->query('ServerContainer')->getSession(), + $c->query('ServerContainer')->getSecureRandom(), $c->query('UserId') ); }); diff --git a/settings/Controller/AuthSettingsController.php b/settings/Controller/AuthSettingsController.php index 1d874193d36..71868b7688d 100644 --- a/settings/Controller/AuthSettingsController.php +++ b/settings/Controller/AuthSettingsController.php @@ -22,41 +22,56 @@ namespace OC\Settings\Controller; +use OC\AppFramework\Http; +use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Token\IProvider; +use OC\Authentication\Token\IToken; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; +use OCP\ISession; use OCP\IUserManager; +use OCP\Security\ISecureRandom; +use OCP\Session\Exceptions\SessionNotAvailableException; class AuthSettingsController extends Controller { /** @var IProvider */ private $tokenProvider; - /** - * @var IUserManager - */ + /** @var IUserManager */ private $userManager; + /** @var ISession */ + private $session; + /** @var string */ private $uid; + /** @var ISecureRandom */ + private $random; + /** * @param string $appName * @param IRequest $request * @param IProvider $tokenProvider * @param IUserManager $userManager + * @param ISession $session + * @param ISecureRandom $random * @param string $uid */ - public function __construct($appName, IRequest $request, IProvider $tokenProvider, IUserManager $userManager, $uid) { + public function __construct($appName, IRequest $request, IProvider $tokenProvider, IUserManager $userManager, ISession $session, ISecureRandom $random, $uid) { parent::__construct($appName, $request); $this->tokenProvider = $tokenProvider; $this->userManager = $userManager; $this->uid = $uid; + $this->session = $session; + $this->random = $random; } /** * @NoAdminRequired + * @NoSubadminRequired * * @return JSONResponse */ @@ -68,4 +83,52 @@ class AuthSettingsController extends Controller { return $this->tokenProvider->getTokenByUser($user); } + /** + * @NoAdminRequired + * @NoSubadminRequired + * + * @return JSONResponse + */ + public function create($name) { + try { + $sessionId = $this->session->getId(); + } catch (SessionNotAvailableException $ex) { + $resp = new JSONResponse(); + $resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE); + return $resp; + } + + try { + $sessionToken = $this->tokenProvider->getToken($sessionId); + $password = $this->tokenProvider->getPassword($sessionToken, $sessionId); + } catch (InvalidTokenException $ex) { + $resp = new JSONResponse(); + $resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE); + return $resp; + } + + $token = $this->generateRandomDeviceToken(); + $deviceToken = $this->tokenProvider->generateToken($token, $this->uid, $password, $name, IToken::PERMANENT_TOKEN); + + return [ + 'token' => $token, + 'deviceToken' => $deviceToken + ]; + } + + /** + * Return a 20 digit device password + * + * Example: ABCDE-FGHIJ-KLMNO-PQRST + * + * @return string + */ + private function generateRandomDeviceToken() { + $groups = []; + for ($i = 0; $i < 4; $i++) { + $groups[] = $this->random->generate(5, implode('', range('A', 'Z'))); + } + return implode('-', $groups); + } + } diff --git a/settings/css/settings.css b/settings/css/settings.css index be61265935e..418c5f95517 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -100,10 +100,6 @@ input#identity { table.nostyle label { margin-right: 2em; } table.nostyle td { padding: 0.2em 0; } -#sessions, -#devices { - min-height: 180px; -} #sessions table, #devices table { width: 100%; @@ -114,6 +110,24 @@ table.nostyle td { padding: 0.2em 0; } #devices table th { font-weight: 800; } +#sessions table th, +#sessions table td, +#devices table th, +#devices table td { + padding: 10px; +} + +#sessions .token-list td, +#devices .token-list td { + border-top: 1px solid #DDD; +} + +#device-new-token { + padding: 10px; + font-family: monospace; + font-size: 1.4em; + background-color: lightyellow; +} /* USERS */ #newgroup-init a span { margin-left: 20px; } diff --git a/settings/js/authtoken_view.js b/settings/js/authtoken_view.js index 0ca16821233..8ca38d80d84 100644 --- a/settings/js/authtoken_view.js +++ b/settings/js/authtoken_view.js @@ -1,4 +1,4 @@ -/* global Backbone, Handlebars */ +/* global Backbone, Handlebars, moment */ /** * @author Christoph Wurst <christoph@owncloud.com> @@ -20,16 +20,16 @@ * */ -(function(OC, _, Backbone, $, Handlebars) { +(function(OC, _, Backbone, $, Handlebars, moment) { 'use strict'; OC.Settings = OC.Settings || {}; var TEMPLATE_TOKEN = - '<tr>' - + '<td>{{name}}</td>' - + '<td>{{lastActivity}}</td>' - + '<tr>'; + '<tr>' + + '<td>{{name}}</td>' + + '<td>{{lastActivity}}</td>' + + '<tr>'; var SubView = Backbone.View.extend({ collection: null, @@ -46,48 +46,115 @@ var tokens = this.collection.filter(function(token) { return parseInt(token.get('type')) === _this.type; }); - list.removeClass('icon-loading'); list.html(''); tokens.forEach(function(token) { - var html = _this.template(token.toJSON()); + var viewData = token.toJSON(); + viewData.lastActivity = moment(viewData.lastActivity, 'X'). + format('LLL'); + var html = _this.template(viewData); list.append(html); }); }, + toggleLoading: function(state) { + this.$el.find('.token-list').toggleClass('icon-loading', state); + } }); var AuthTokenView = Backbone.View.extend({ collection: null, - views - : [], + _views: [], + _form: undefined, + _tokenName: undefined, + _addTokenBtn: undefined, + _result: undefined, + _newToken: undefined, + _hideTokenBtn: undefined, + _addingToken: false, initialize: function(options) { this.collection = options.collection; var tokenTypes = [0, 1]; var _this = this; _.each(tokenTypes, function(type) { - _this.views.push(new SubView({ + _this._views.push(new SubView({ el: type === 0 ? '#sessions' : '#devices', type: type, collection: _this.collection })); }); + + this._form = $('#device-token-form'); + this._tokenName = $('#device-token-name'); + this._addTokenBtn = $('#device-add-token'); + this._addTokenBtn.click(_.bind(this._addDeviceToken, this)); + + this._result = $('#device-token-result'); + this._newToken = $('#device-new-token'); + this._hideTokenBtn = $('#device-token-hide'); + this._hideTokenBtn.click(_.bind(this._hideToken, this)); }, render: function() { - _.each(this.views, function(view) { + _.each(this._views, function(view) { view.render(); + view.toggleLoading(false); }); }, reload: function() { + var _this = this; + + _.each(this._views, function(view) { + view.toggleLoading(true); + }); + var loadingTokens = this.collection.fetch(); - var _this = this; $.when(loadingTokens).done(function() { _this.render(); }); + $.when(loadingTokens).fail(function() { + OC.Notification.showTemporary(t('core', 'Error while loading browser sessions and device tokens')); + }); + }, + _addDeviceToken: function() { + var _this = this; + this._toggleAddingToken(true); + + var deviceName = this._tokenName.val(); + var creatingToken = $.ajax(OC.generateUrl('/settings/personal/authtokens'), { + method: 'POST', + data: { + name: deviceName + } + }); + + $.when(creatingToken).done(function(resp) { + _this.collection.add(resp.deviceToken); + _this.render(); + _this._newToken.text(resp.token); + _this._toggleFormResult(false); + _this._tokenName.val(''); + }); + $.when(creatingToken).fail(function() { + OC.Notification.showTemporary(t('core', 'Error while creating device token')); + }); + $.when(creatingToken).always(function() { + _this._toggleAddingToken(false); + }); + }, + _hideToken: function() { + this._toggleFormResult(true); + }, + _toggleAddingToken: function(state) { + this._addingToken = state; + this._addTokenBtn.toggleClass('icon-loading-small', state); + }, + _toggleFormResult: function(showForm) { + this._form.toggleClass('hidden', !showForm); + this._result.toggleClass('hidden', showForm); } }); OC.Settings.AuthTokenView = AuthTokenView; -})(OC, _, Backbone, $, Handlebars); +})(OC, _, Backbone, $, Handlebars, moment); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index a7e86b50a59..4f8d564f549 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -147,6 +147,7 @@ if($_['passwordChangeSupported']) { <tr> <th>Browser</th> <th>Most recent activity</th> + <th></th> </tr> </thead> <tbody class="token-list icon-loading"> @@ -162,11 +163,21 @@ if($_['passwordChangeSupported']) { <tr> <th>Name</th> <th>Most recent activity</th> + <th><a class="icon-delete"></a></th> </tr> </thead> <tbody class="token-list icon-loading"> </tbody> </table> + <p><?php p($l->t('A device password is a passcode that gives an app or device permissions to access your ownCloud account.'));?></p> + <div id="device-token-form"> + <input id="device-token-name" type="text" placeholder="Device name"> + <button id="device-add-token" class="button">Create new device password</button> + </div> + <div id="device-token-result" class="hidden"> + <span id="device-new-token"></span> + <button id="device-token-hide" class="button">Done</button> + </div> </div> <form id="language" class="section"> |