From 9cb231391a60a85e5c3a72d2b8f4851901ea4f32 Mon Sep 17 00:00:00 2001 From: Vishal Banthia Date: Thu, 26 Nov 2015 02:36:09 +0900 Subject: [PATCH] Create seperate database table for AccessTokens to hide jwt token and tokenId from user --- lib/db/api.js | 23 ++++++------ lib/db/tables.js | 11 +++--- lib/units/app/index.js | 23 ++++++++++++ lib/units/websocket/index.js | 3 +- .../stf/tokens/access-token-service.js | 35 ++++++++++++++++++ .../generate-access-token-directive.js | 5 ++- res/app/components/stf/tokens/index.js | 1 + res/app/components/stf/user/user-service.js | 36 ------------------- .../access-tokens/access-tokens-controller.js | 18 +++++----- .../keys/access-tokens/access-tokens.jade | 12 +++---- res/app/settings/keys/access-tokens/index.js | 1 + 11 files changed, 97 insertions(+), 71 deletions(-) create mode 100644 res/app/components/stf/tokens/access-token-service.js diff --git a/lib/db/api.js b/lib/db/api.js index 020a0642..ed2cd6b4 100644 --- a/lib/db/api.js +++ b/lib/db/api.js @@ -309,20 +309,23 @@ dbapi.loadDevice = function(serial) { } dbapi.saveUserAccessToken = function(email, token) { - return db.run(r.table('users').get(email).update({ - accessTokens: r.row('accessTokens').default([]).append({ - title: token.title - , tokenId: token.tokenId - , jwt: token.jwt - }) + return db.run(r.table('accessTokens').insert({ + email: email + , id: token.id + , title: token.title + , jwt: token.jwt })) } dbapi.removeUserAccessToken = function(email, title) { - return db.run(r.table('users').get(email).update({ - accessTokens: r.row('accessTokens').default([]).filter(function(token) { - return token('title').ne(title) - }) + return db.run(r.table('accessTokens').getAll(email, { + index: 'email' + }).filter({"title": title}).delete()) +} + +dbapi.loadAccessTokens = function(email) { + return db.run(r.table('accessTokens').getAll(email, { + index: 'email' })) } diff --git a/lib/db/tables.js b/lib/db/tables.js index cbdf5683..231f5971 100644 --- a/lib/db/tables.js +++ b/lib/db/tables.js @@ -8,17 +8,18 @@ module.exports = { indexFunction: function(user) { return user('adbKeys')('fingerprint') } - , accessTokens: { - indexFunction: function(user) { - return user('accessTokens')('tokenId') - } - } , options: { multi: true } } } } +, accessTokens: { + primaryKey: 'id' + , indexes: { + email: null + } + } , vncauth: { primaryKey: 'password' , indexes: { diff --git a/lib/units/app/index.js b/lib/units/app/index.js index 7cc8ae25..13d10071 100644 --- a/lib/units/app/index.js +++ b/lib/units/app/index.js @@ -200,6 +200,29 @@ module.exports = function(options) { }) }) + app.get('/app/api/v1/accessTokens', function(req, res) { + dbapi.loadAccessTokens(req.user.email) + .then(function(cursor) { + return Promise.promisify(cursor.toArray, cursor)() + .then(function(list) { + var titles = [] + list.forEach(function(token) { + titles.push(token.title) + }) + res.json({ + success: true + , titles: titles + }) + }) + }) + .catch(function(err) { + log.error('Failed to load tokens: ', err.stack) + res.json(500, { + success: false + }) + }) + }) + server.listen(options.port) log.info('Listening on port %d', options.port) } diff --git a/lib/units/websocket/index.js b/lib/units/websocket/index.js index e62a99e3..883ff45f 100644 --- a/lib/units/websocket/index.js +++ b/lib/units/websocket/index.js @@ -352,14 +352,13 @@ module.exports = function(options) { return dbapi.saveUserAccessToken(user.email, { title: title - , tokenId: tokenId + , id: tokenId , jwt: jwt }) .then(function() { socket.emit('user.keys.accessToken.generated', { title: title , tokenId: tokenId - , jwt: jwt }) }) }) diff --git a/res/app/components/stf/tokens/access-token-service.js b/res/app/components/stf/tokens/access-token-service.js new file mode 100644 index 00000000..38b9db6f --- /dev/null +++ b/res/app/components/stf/tokens/access-token-service.js @@ -0,0 +1,35 @@ +module.exports = function AccessTokenServiceFactory( + $rootScope +, $http +, socket +) { + var AccessTokenService = {} + + AccessTokenService.getAccessTokens = function() { + return $http.get('/app/api/v1/accessTokens') + } + + AccessTokenService.generateAccessToken = function(title) { + socket.emit('user.keys.accessToken.generate', { + title: title + }) + } + + AccessTokenService.removeAccessToken = function(title) { + socket.emit('user.keys.accessToken.remove', { + title: title + }) + } + + socket.on('user.keys.accessToken.generated', function(token) { + $rootScope.$broadcast('user.keys.accessTokens.generated', token) + $rootScope.$apply() + }) + + socket.on('user.keys.accessToken.removed', function() { + $rootScope.$broadcast('user.keys.accessTokens.updated') + $rootScope.$apply() + }) + + return AccessTokenService +} diff --git a/res/app/components/stf/tokens/generate-access-token/generate-access-token-directive.js b/res/app/components/stf/tokens/generate-access-token/generate-access-token-directive.js index d674f9bb..2e034f08 100644 --- a/res/app/components/stf/tokens/generate-access-token/generate-access-token-directive.js +++ b/res/app/components/stf/tokens/generate-access-token/generate-access-token-directive.js @@ -4,16 +4,15 @@ module.exports = function generateAccessTokenDirective() { replace: true, scope: { showGenerate: '=', - showClipboard: '=', }, template: require('./generate-access-token.jade'), - controller: function($scope, UserService) { + controller: function($scope, AccessTokenService) { $scope.generateForm = { title: '' } $scope.generateToken = function () { - UserService.generateAccessToken($scope.generateForm.title) + AccessTokenService.generateAccessToken($scope.generateForm.title) $scope.closeGenerateToken() } diff --git a/res/app/components/stf/tokens/index.js b/res/app/components/stf/tokens/index.js index a4ad4f75..11902070 100644 --- a/res/app/components/stf/tokens/index.js +++ b/res/app/components/stf/tokens/index.js @@ -1,3 +1,4 @@ module.exports = angular.module('stf.tokens', [ require('./generate-access-token').name, ]) +.factory('AccessTokenService', require('./access-token-service')) diff --git a/res/app/components/stf/user/user-service.js b/res/app/components/stf/user/user-service.js index 766cafc7..e1de7c07 100644 --- a/res/app/components/stf/user/user-service.js +++ b/res/app/components/stf/user/user-service.js @@ -8,22 +8,6 @@ module.exports = function UserServiceFactory( var user = UserService.currentUser = AppState.user - UserService.getAccessTokens = function() { - return (user.accessTokens || (user.accessTokens = [])) - } - - UserService.generateAccessToken = function(title) { - socket.emit('user.keys.accessToken.generate', { - title: title - }) - } - - UserService.removeAccessToken = function(title) { - socket.emit('user.keys.accessToken.remove', { - title: title - }) - } - UserService.getAdbKeys = function() { return (user.adbKeys || (user.adbKeys = [])) } @@ -40,26 +24,6 @@ module.exports = function UserServiceFactory( socket.emit('user.keys.adb.remove', key) } - // socket.on('user.keys.accessToken.generated', function(token) { - // UserService.getAccessTokens().push(token) - // $rootScope.$broadcast('user.keys.accessTokens.updated', user.accessTokens) - // $rootScope.$apply() - // }) - - socket.on('user.keys.accessToken.generated', function(token) { - $rootScope.$broadcast('user.keys.accessTokens.generated', token) - $rootScope.$apply() - }) - - socket.on('user.keys.accessToken.removed', function(title) { - user.accessTokens = UserService.getAccessTokens().filter(function(token) { - return token.title !== title - }) - $rootScope.$broadcast('user.keys.accessTokens.updated', user.accessTokens) - $rootScope.$apply() - }) - - socket.on('user.keys.adb.added', function(key) { UserService.getAdbKeys().push(key) $rootScope.$broadcast('user.keys.adb.updated', user.adbKeys) diff --git a/res/app/settings/keys/access-tokens/access-tokens-controller.js b/res/app/settings/keys/access-tokens/access-tokens-controller.js index f34b88a6..db48cff3 100644 --- a/res/app/settings/keys/access-tokens/access-tokens-controller.js +++ b/res/app/settings/keys/access-tokens/access-tokens-controller.js @@ -1,28 +1,28 @@ -module.exports = function AccessTokensCtrl($scope, $http, UserService) { +module.exports = function AccessTokensCtrl($scope, AccessTokenService) { - $scope.accessTokens = [] + $scope.accessTokenTitles = [] $scope.newToken = null function updateTokens() { - $scope.accessTokens = UserService.getAccessTokens() + AccessTokenService.getAccessTokens() + .success(function(response) { + $scope.accessTokenTitles = response.titles || [] + }) } $scope.removeToken = function (title) { - UserService.removeAccessToken(title) + AccessTokenService.removeAccessToken(title) } - $scope.tokenGenerated = function() { - $scope.accessToken = '' + $scope.closeGenerated = function() { $scope.showGenerated = false - UserService.getAccessTokens().push($scope.newToken) $scope.newToken = null updateTokens() } $scope.$on('user.keys.accessTokens.generated', function(event, token) { - $scope.showGenerated = true - $scope.accessTokenId = token.tokenId $scope.newToken = token + $scope.showGenerated = true }) $scope.$on('user.keys.accessTokens.updated', updateTokens) diff --git a/res/app/settings/keys/access-tokens/access-tokens.jade b/res/app/settings/keys/access-tokens/access-tokens.jade index e9d0d218..2d6d6456 100644 --- a/res/app/settings/keys/access-tokens/access-tokens.jade +++ b/res/app/settings/keys/access-tokens/access-tokens.jade @@ -14,7 +14,7 @@ .widget-content.padded nothing-to-show(icon='fa-key', message='{{"No access tokens" | translate}}', - ng-if='!accessTokens.length && !showGenerate && !showGenerated') + ng-if='!accessTokenTitles.length && !showGenerate && !showGenerated') generate-access-token(show-clipboard='true', show-generate='showGenerate') @@ -24,17 +24,17 @@ span   span(translate) Make sure to copy your access token now. You won't be able to see it again! br - button.btn.pull-right.btn-primary.btn-sm(ng-click='tokenGenerated()') + button.btn.pull-right.btn-primary.btn-sm(ng-click='closeGenerated()') i.fa.fa-check.fa-fw - textarea(readonly, rows='1', text-focus-select, ng-model='accessTokenId').form-control.token-id-textarea + textarea(readonly, rows='1', text-focus-select, ng-model='newToken.tokenId').form-control.token-id-textarea ul.list-group.key-list - li.list-group-item(ng-repeat='token in accessTokens').animate-repeat + li.list-group-item(ng-repeat='title in accessTokenTitles').animate-repeat a i.fa.fa-key.fa-2x.fa-fw.key-list-icon .key-list-details.selectable - .key-list-title(ng-bind='token.title') + .key-list-title(ng-bind='title') - button.btn.btn-xs.btn-danger-outline.pull-right.key-list-remove(ng-click='removeToken(token.title)') + button.btn.btn-xs.btn-danger-outline.pull-right.key-list-remove(ng-click='removeToken(title)') i.fa.fa-trash-o span(translate) Remove diff --git a/res/app/settings/keys/access-tokens/index.js b/res/app/settings/keys/access-tokens/index.js index e92ade13..f2bbc059 100644 --- a/res/app/settings/keys/access-tokens/index.js +++ b/res/app/settings/keys/access-tokens/index.js @@ -2,6 +2,7 @@ require('./access-tokens.css') module.exports = angular.module('stf.settings.keys.access-tokens', [ require('stf/common-ui').name, + require('stf/tokens').name, require('stf/tokens/generate-access-token').name ]) .run(["$templateCache", function ($templateCache) {