diff --git a/.gitignore b/.gitignore index 7701503b05..87beaa63c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .vs node_modules +npm-debug.log diff --git a/src/background.js b/src/background.js index 077ada5ca4..70cc84ddfe 100644 --- a/src/background.js +++ b/src/background.js @@ -1,3 +1,4 @@ var cryptoService = new CryptoService(); var tokenService = new TokenService(); -var userService = new UserService(tokenService); +var apiService = new ApiService(tokenService); +var userService = new UserService(tokenService, apiService); diff --git a/src/manifest.json b/src/manifest.json index 2e50e396c0..737331e265 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -13,11 +13,13 @@ }, "background": { "scripts": [ + "node_modules/jquery/dist/jquery.min.js", "node_modules/sjcl/sjcl.js", "node_modules/sjcl/core/cbc.js", "node_modules/sjcl/core/bitArray.js", "services/cryptoService.js", "services/tokenService.js", + "services/apiService.js", "services/userService.js", "background.js" ] diff --git a/src/package.json b/src/package.json index 861d05266a..a61915e9b0 100644 --- a/src/package.json +++ b/src/package.json @@ -4,6 +4,7 @@ "devDependencies": { "ionic-framework-v1": "1.3.1", "sjcl": "1.0.3", - "angular-jwt": "0.0.9" + "angular-jwt": "0.0.9", + "jquery": "3.1.0" } } diff --git a/src/popup/app/services/apiService.js b/src/popup/app/services/apiService.js index f1a1ef268c..b6eaea7226 100644 --- a/src/popup/app/services/apiService.js +++ b/src/popup/app/services/apiService.js @@ -6,42 +6,21 @@ _apiUri = appSettings.apiUri; _service.sites = $resource(_apiUri + '/sites/:id', {}, { - get: { method: 'GET', params: { id: '@id' } }, - list: { method: 'GET', params: {} }, post: { method: 'POST', params: {} }, put: { method: 'POST', params: { id: '@id' } }, del: { url: _apiUri + '/sites/:id/delete', method: 'POST', params: { id: '@id' } } }); _service.folders = $resource(_apiUri + '/folders/:id', {}, { - get: { method: 'GET', params: { id: '@id' } }, - list: { method: 'GET', params: {} }, post: { method: 'POST', params: {} }, put: { method: 'POST', params: { id: '@id' } }, del: { url: _apiUri + '/folders/:id/delete', method: 'POST', params: { id: '@id' } } }); - _service.ciphers = $resource(_apiUri + '/ciphers/:id', {}, { - get: { method: 'GET', params: { id: '@id' } }, - list: { method: 'GET', params: {} }, - 'import': { url: _apiUri + '/ciphers/import', method: 'POST', params: {} }, - favorite: { url: _apiUri + '/ciphers/:id/favorite', method: 'POST', params: { id: '@id' } }, - del: { url: _apiUri + '/ciphers/:id/delete', method: 'POST', params: { id: '@id' } } - }); - _service.accounts = $resource(_apiUri + '/accounts', {}, { register: { url: _apiUri + '/accounts/register', method: 'POST', params: {} }, - emailToken: { url: _apiUri + '/accounts/email-token', method: 'POST', params: {} }, - email: { url: _apiUri + '/accounts/email', method: 'POST', params: {} }, - putPassword: { url: _apiUri + '/accounts/password', method: 'POST', params: {} }, getProfile: { url: _apiUri + '/accounts/profile', method: 'GET', params: {} }, - putProfile: { url: _apiUri + '/accounts/profile', method: 'POST', params: {} }, - getTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'GET', params: {} }, - putTwoFactor: { url: _apiUri + '/accounts/two-factor', method: 'POST', params: {} }, - postPasswordHint: { url: _apiUri + '/accounts/password-hint', method: 'POST', params: {} }, - putSecurityStamp: { url: _apiUri + '/accounts/security-stamp', method: 'POST', params: {} }, - 'import': { url: _apiUri + '/accounts/import', method: 'POST', params: {} }, - postDelete: { url: _apiUri + '/accounts/delete', method: 'POST', params: {} } + postPasswordHint: { url: _apiUri + '/accounts/password-hint', method: 'POST', params: {} } }); _service.auth = $resource(_apiUri + '/auth', {}, { diff --git a/src/popup/index.html b/src/popup/index.html index 5903f60491..099cbd59c1 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -5,10 +5,10 @@ bitwarden - - - - + + + + diff --git a/src/services/apiService.js b/src/services/apiService.js new file mode 100644 index 0000000000..06eb98ab43 --- /dev/null +++ b/src/services/apiService.js @@ -0,0 +1,20 @@ +function ApiService(tokenService) { + this.baseUrl = 'https://api.bitwarden.com'; + this.tokenService = tokenService; +}; + +!function () { + ApiService.prototype.getProfile = function (success, error) { + var self = this; + this.tokenService.getToken(function(token) { + $.ajax({ + type: 'GET', + url: self.baseUrl + '/accounts/profile', + data: 'access_token=' + token, + dataType: 'json', + success: success, + error: error + }); + }); + }; +}(); diff --git a/src/services/siteService.js b/src/services/siteService.js new file mode 100644 index 0000000000..131225045a --- /dev/null +++ b/src/services/siteService.js @@ -0,0 +1,104 @@ +function TokenService() { + +}; + +!function () { + var _token; + + TokenService.prototype.setToken = function (token, callback) { + if (!callback || typeof callback !== 'function') { + throw 'callback function required'; + } + + _token = token; + chrome.storage.local.set({ + 'authBearer': token + }, function () { + callback(); + }); + }; + + TokenService.prototype.getToken = function (callback) { + if (!callback || typeof callback !== 'function') { + throw 'callback function required'; + } + + if (_token) { + return callback(_token); + } + + chrome.storage.local.get('authBearer', function (obj) { + if (obj && obj.authBearer) { + _token = obj.authBearer; + } + + return callback(_token); + }); + }; + + TokenService.prototype.clearToken = function (callback) { + if (!callback || typeof callback !== 'function') { + throw 'callback function required'; + } + + _token = null; + chrome.storage.local.remove('authBearer', function () { + callback(); + }); + }; + + // jwthelper methods + // ref https://github.com/auth0/angular-jwt/blob/master/src/angularJwt/services/jwt.js + + TokenService.prototype.decodeToken = function (token) { + var parts = token.split('.'); + + if (parts.length !== 3) { + throw new Error('JWT must have 3 parts'); + } + + var decoded = urlBase64Decode(parts[1]); + if (!decoded) { + throw new Error('Cannot decode the token'); + } + + return JSON.parse(decoded); + }; + + TokenService.prototype.getTokenExpirationDate = function (token) { + var decoded = this.decodeToken(token); + + if (typeof decoded.exp === "undefined") { + return null; + } + + var d = new Date(0); // The 0 here is the key, which sets the date to the epoch + d.setUTCSeconds(decoded.exp); + + return d; + }; + + TokenService.prototype.isTokenExpired = function (token, offsetSeconds) { + var d = this.getTokenExpirationDate(token); + offsetSeconds = offsetSeconds || 0; + if (d === null) { + return false; + } + + // Token expired? + return !(d.valueOf() > (new Date().valueOf() + (offsetSeconds * 1000))); + }; + + function urlBase64Decode(str) { + var output = str.replace(/-/g, '+').replace(/_/g, '/'); + switch (output.length % 4) { + case 0: { break; } + case 2: { output += '=='; break; } + case 3: { output += '='; break; } + default: { + throw 'Illegal base64url string!'; + } + } + return window.decodeURIComponent(escape(window.atob(output))); //polyfill https://github.com/davidchambers/Base64.js + }; +}(); diff --git a/src/services/userService.js b/src/services/userService.js index efea59df29..65090289ea 100644 --- a/src/services/userService.js +++ b/src/services/userService.js @@ -1,5 +1,6 @@ -function UserService(tokenService) { +function UserService(tokenService, apiService) { this.tokenService = tokenService; + this.apiService = apiService; }; !function () { @@ -43,10 +44,9 @@ loadProfile(profile, callback); } else if (!twoFactor && !profile) { - loadProfile({}, callback); - //apiService.accounts.getProfile({}, function (response) { - // loadProfile(response, callback); - //}); + this.apiService.getProfile(function (response) { + loadProfile(response, callback); + }); } });