diff --git a/src/background.html b/src/background.html index 6f9e86d4..820ba065 100644 --- a/src/background.html +++ b/src/background.html @@ -24,6 +24,7 @@ + diff --git a/src/background.js b/src/background.js index 18afd4e2..37e02436 100644 --- a/src/background.js +++ b/src/background.js @@ -1,5 +1,11 @@ -var isBackground = true; +var isBackground = true, + loginToAutoFill = null, + pageDetailsToAutoFill = [], + autofillTimeout = null, + menuOptionsLoaded = []; + var bg_loginsToAdd = []; + var bg_utilsService = new UtilsService(); var bg_i18nService = new i18nService(bg_utilsService); var bg_constantsService = new ConstantsService(bg_i18nService); @@ -7,6 +13,7 @@ var bg_cryptoService = new CryptoService(bg_constantsService); var bg_tokenService = new TokenService(); var bg_appIdService = new AppIdService(); var bg_apiService = new ApiService(bg_tokenService, bg_appIdService, bg_utilsService, bg_constantsService, logout); +var bg_environmentService = new EnvironmentService(bg_constantsService, bg_apiService); var bg_userService = new UserService(bg_tokenService, bg_apiService, bg_cryptoService); var bg_settingsService = new SettingsService(bg_userService); var bg_loginService = new LoginService(bg_cryptoService, bg_userService, bg_apiService, bg_settingsService); @@ -45,11 +52,6 @@ if (chrome.commands) { }); } -var loginToAutoFill = null, - pageDetailsToAutoFill = [], - autofillTimeout = null, - menuOptionsLoaded = []; - chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) { if (msg.command === 'loggedIn' || msg.command === 'unlocked' || msg.command === 'locked') { setIcon(); @@ -108,28 +110,6 @@ chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) { } }); -setIcon(); -function setIcon() { - bg_userService.isAuthenticated(function (isAuthenticated) { - bg_cryptoService.getKey().then(function (key) { - var suffix = ''; - if (!isAuthenticated) { - suffix = '_gray'; - } - else if (!key) { - suffix = '_locked'; - } - - chrome.browserAction.setIcon({ - path: { - '19': 'images/icon19' + suffix + '.png', - '38': 'images/icon38' + suffix + '.png', - } - }); - }); - }); -} - if (chrome.runtime.onInstalled) { chrome.runtime.onInstalled.addListener(function (details) { ga('send', { @@ -143,6 +123,89 @@ if (chrome.runtime.onInstalled) { }); } +chrome.tabs.onActivated.addListener(function (activeInfo) { + refreshBadgeAndMenu(); +}); + +var onReplacedRan = false; +chrome.tabs.onReplaced.addListener(function (addedTabId, removedTabId) { + if (onReplacedRan) { + return; + } + onReplacedRan = true; + checkbg_loginsToAdd(); + refreshBadgeAndMenu(); +}); + +var onUpdatedRan = false; +chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { + if (onUpdatedRan) { + return; + } + onUpdatedRan = true; + checkbg_loginsToAdd(); + refreshBadgeAndMenu(); +}); + +chrome.windows.onFocusChanged.addListener(function (windowId) { + if (windowId === null || windowId < 0) { + return; + } + + refreshBadgeAndMenu(); +}); + +chrome.contextMenus.onClicked.addListener(function (info, tab) { + if (info.menuItemId === 'generate-password') { + ga('send', { + hitType: 'event', + eventAction: 'Generated Password From Context Menu' + }); + bg_passwordGenerationService.getOptions().then(function (options) { + var password = bg_passwordGenerationService.generatePassword(options); + bg_utilsService.copyToClipboard(password); + }); + } + else if (info.parentMenuItemId === 'autofill' || info.parentMenuItemId === 'copy-username' || + info.parentMenuItemId === 'copy-password') { + var id = info.menuItemId.split('_')[1]; + if (id === 'noop') { + return; + } + + bg_loginService.getAllDecrypted().then(function (logins) { + for (var i = 0; i < logins.length; i++) { + if (logins[i].id === id) { + if (info.parentMenuItemId === 'autofill') { + ga('send', { + hitType: 'event', + eventAction: 'Autofilled From Context Menu' + }); + startAutofillPage(logins[i]); + } + else if (info.parentMenuItemId === 'copy-username') { + ga('send', { + hitType: 'event', + eventAction: 'Copied Username From Context Menu' + }); + bg_utilsService.copyToClipboard(logins[i].username); + } + else if (info.parentMenuItemId === 'copy-password') { + ga('send', { + hitType: 'event', + eventAction: 'Copied Password From Context Menu' + }); + bg_utilsService.copyToClipboard(logins[i].password); + } + return; + } + } + }, function () { + + }); + } +}); + var buildingContextMenu = false; function buildContextMenu(callback) { if (buildingContextMenu) { @@ -211,37 +274,26 @@ function buildContextMenu(callback) { }); } -chrome.tabs.onActivated.addListener(function (activeInfo) { - refreshBadgeAndMenu(); -}); +function setIcon() { + bg_userService.isAuthenticated(function (isAuthenticated) { + bg_cryptoService.getKey().then(function (key) { + var suffix = ''; + if (!isAuthenticated) { + suffix = '_gray'; + } + else if (!key) { + suffix = '_locked'; + } -var onReplacedRan = false; -chrome.tabs.onReplaced.addListener(function (addedTabId, removedTabId) { - if (onReplacedRan) { - return; - } - onReplacedRan = true; - checkbg_loginsToAdd(); - refreshBadgeAndMenu(); -}); - -var onUpdatedRan = false; -chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { - if (onUpdatedRan) { - return; - } - onUpdatedRan = true; - checkbg_loginsToAdd(); - refreshBadgeAndMenu(); -}); - -chrome.windows.onFocusChanged.addListener(function (windowId) { - if (windowId === null || windowId < 0) { - return; - } - - refreshBadgeAndMenu(); -}); + chrome.browserAction.setIcon({ + path: { + '19': 'images/icon19' + suffix + '.png', + '38': 'images/icon38' + suffix + '.png', + } + }); + }); + }); +} function refreshBadgeAndMenu() { chrome.tabs.query({ active: true, windowId: chrome.windows.WINDOW_ID_CURRENT }, function (tabs) { @@ -327,57 +379,6 @@ function loadMenuAndUpdateBadge(url, tabId, contextMenuEnabled) { }); } -chrome.contextMenus.onClicked.addListener(function (info, tab) { - if (info.menuItemId === 'generate-password') { - ga('send', { - hitType: 'event', - eventAction: 'Generated Password From Context Menu' - }); - bg_passwordGenerationService.getOptions().then(function (options) { - var password = bg_passwordGenerationService.generatePassword(options); - bg_utilsService.copyToClipboard(password); - }); - } - else if (info.parentMenuItemId === 'autofill' || info.parentMenuItemId === 'copy-username' || - info.parentMenuItemId === 'copy-password') { - var id = info.menuItemId.split('_')[1]; - if (id === 'noop') { - return; - } - - bg_loginService.getAllDecrypted().then(function (logins) { - for (var i = 0; i < logins.length; i++) { - if (logins[i].id === id) { - if (info.parentMenuItemId === 'autofill') { - ga('send', { - hitType: 'event', - eventAction: 'Autofilled From Context Menu' - }); - startAutofillPage(logins[i]); - } - else if (info.parentMenuItemId === 'copy-username') { - ga('send', { - hitType: 'event', - eventAction: 'Copied Username From Context Menu' - }); - bg_utilsService.copyToClipboard(logins[i].username); - } - else if (info.parentMenuItemId === 'copy-password') { - ga('send', { - hitType: 'event', - eventAction: 'Copied Password From Context Menu' - }); - bg_utilsService.copyToClipboard(logins[i].password); - } - return; - } - } - }, function () { - - }); - } -}); - function messageCurrentTab(command, data) { chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { var tabId = null; @@ -457,7 +458,6 @@ function addLogin(login, tab) { }); } -cleanupbg_loginsToAdd(); function cleanupbg_loginsToAdd() { for (var i = bg_loginsToAdd.length - 1; i >= 0; i--) { if (bg_loginsToAdd[i].expires < new Date()) { @@ -679,9 +679,6 @@ function logout(expired, callback) { }); } -// Sync polling - -fullSync(true); function fullSync(override) { override = override || false; bg_syncService.getLastSync(function (lastSync) { @@ -695,3 +692,11 @@ function fullSync(override) { }); setTimeout(fullSync, 5 * 60 * 1000); // check every 5 minutes } + +// Bootstrap + +bg_environmentService.setUrlsFromStorage(function () { + setIcon(); + cleanupbg_loginsToAdd(); + fullSync(true); +}); diff --git a/src/popup/app/accounts/accountsLoginTwoFactorController.js b/src/popup/app/accounts/accountsLoginTwoFactorController.js index 04290c66..668f0faf 100644 --- a/src/popup/app/accounts/accountsLoginTwoFactorController.js +++ b/src/popup/app/accounts/accountsLoginTwoFactorController.js @@ -2,20 +2,17 @@ .module('bit.accounts') .controller('accountsLoginTwoFactorController', function ($scope, $state, authService, toastr, utilsService, SweetAlert, - $analytics, i18nService, $stateParams, $filter, constantsService, $timeout, $window, cryptoService, apiService) { + $analytics, i18nService, $stateParams, $filter, constantsService, $timeout, $window, cryptoService, apiService, + environmentService) { $scope.i18n = i18nService; utilsService.initListSectionItemListeners($(document), angular); var customWebVaultUrl = null; - var storedBaseUrl = $window.localStorage.getItem(constantsService.baseUrlKey); - if (storedBaseUrl) { - customWebVaultUrl = storedBaseUrl; + if (environmentService.baseUrl) { + customWebVaultUrl = environmentService.baseUrl; } - else { - var storedWebVaultUrl = $window.localStorage.getItem(constantsService.webVaultUrlKey); - if (storedWebVaultUrl) { - customWebVaultUrl = storedWebVaultUrl; - } + else if (environmentService.webVaultUrl) { + customWebVaultUrl = environmentService.webVaultUrl; } var u2f = new U2f(customWebVaultUrl, function (data) { diff --git a/src/popup/app/services/backgroundService.js b/src/popup/app/services/backgroundService.js index 95ea4a7e..06a10342 100644 --- a/src/popup/app/services/backgroundService.js +++ b/src/popup/app/services/backgroundService.js @@ -48,4 +48,7 @@ }) .factory('totpService', function () { return chrome.extension.getBackgroundPage().bg_totpService; + }) + .factory('environmentService', function () { + return chrome.extension.getBackgroundPage().bg_environmentService; }); diff --git a/src/popup/app/settings/settingsEnvironmentController.js b/src/popup/app/settings/settingsEnvironmentController.js index 1fc6462d..653f3c63 100644 --- a/src/popup/app/settings/settingsEnvironmentController.js +++ b/src/popup/app/settings/settingsEnvironmentController.js @@ -1,60 +1,34 @@ angular .module('bit.settings') - .controller('settingsEnvironmentController', function ($scope, i18nService, $analytics, constantsService, utilsService, - $window, apiService, toastr) { + .controller('settingsEnvironmentController', function ($scope, i18nService, $analytics, utilsService, + environmentService, toastr, $timeout) { $scope.i18n = i18nService; utilsService.initListSectionItemListeners($(document), angular); - $scope.baseUrl = $window.localStorage.getItem(constantsService.baseUrlKey) || ''; - $scope.webVaultUrl = $window.localStorage.getItem(constantsService.webVaultUrlKey) || ''; - $scope.apiUrl = $window.localStorage.getItem(constantsService.apiUrlKey) || ''; - $scope.identityUrl = $window.localStorage.getItem(constantsService.identityUrlKey) || ''; + $scope.baseUrl = environmentService.baseUrl || ''; + $scope.webVaultUrl = environmentService.webVaultUrl || ''; + $scope.apiUrl = environmentService.apiUrl || ''; + $scope.identityUrl = environmentService.identityUrl || ''; $scope.save = function () { - if ($scope.baseUrl && $scope.baseUrl !== '') { - $scope.baseUrl = formatUrl($scope.baseUrl); - $window.localStorage.setItem(constantsService.baseUrlKey, $scope.baseUrl); - } - else { - $window.localStorage.removeItem(constantsService.baseUrlKey); - } + environmentService.setUrls({ + base: $scope.baseUrl, + api: $scope.apiUrl, + identity: $scope.identityUrl, + webVault: $scope.webVaultUrl + }, function (resUrls) { + $timeout(function () { + // re-set urls since service can change them, ex: prefixing https:// + $scope.baseUrl = resUrls.base; + $scope.apiUrl = resUrls.api; + $scope.identityUrl = resUrls.identity; + $scope.webVaultUrl = resUrls.webVault; - if ($scope.webVaultUrl && $scope.webVaultUrl !== '') { - $scope.webVaultUrl = formatUrl($scope.webVaultUrl); - $window.localStorage.setItem(constantsService.webVaultUrlKey, $scope.webVaultUrl); - } - else { - $window.localStorage.removeItem(constantsService.webVaultUrlKey); - } - - if ($scope.apiUrl && $scope.apiUrl !== '') { - $scope.apiUrl = formatUrl($scope.apiUrl); - $window.localStorage.setItem(constantsService.apiUrlKey, $scope.apiUrl); - } - else { - $window.localStorage.removeItem(constantsService.apiUrlKey); - } - - if ($scope.identityUrl && $scope.identityUrl !== '') { - $scope.identityUrl = formatUrl($scope.identityUrl); - $window.localStorage.setItem(constantsService.identityUrlKey, $scope.identityUrl); - } - else { - $window.localStorage.removeItem(constantsService.identityUrlKey); - } - - apiService.setUrls(); - $analytics.eventTrack('Set Environment URLs'); - toastr.success(i18nService.environmentSaved); + $analytics.eventTrack('Set Environment URLs'); + toastr.success(i18nService.environmentSaved); + }); + }); }; - - function formatUrl(url) { - url = url.replace(/\/+$/g, ''); - if (!url.startsWith("http://") && !url.startsWith('https://')) { - url = 'https://' + url; - } - return url; - } }); diff --git a/src/services/apiService.js b/src/services/apiService.js index 2d2bfbdd..cfc43b1e 100644 --- a/src/services/apiService.js +++ b/src/services/apiService.js @@ -5,53 +5,49 @@ function ApiService(tokenService, appIdService, utilsService, constantsService, this.utilsService = utilsService; this.constantsService = constantsService; + this.urlsSet = false; + this.baseUrl = null; + this.identityBaseUrl = null; + initApiService(); - this.setUrls(); } function initApiService() { - ApiService.prototype.setUrls = function () { - try { - var storedBaseUrl = window.localStorage.getItem(this.constantsService.baseUrlKey); + ApiService.prototype.setUrls = function (urls) { + var self = this; + self.urlsSet = true; - if (storedBaseUrl) { - this.baseUrl = storedBaseUrl + '/api'; - this.identityBaseUrl = storedBaseUrl + '/identity'; - return; - } - - var storedApiUrl = window.localStorage.getItem(this.constantsService.apiUrlKey); - var storedIdentityUrl = window.localStorage.getItem(this.constantsService.identityUrlKey); - if (storedApiUrl && storedIdentityUrl) { - this.baseUrl = storedApiUrl; - this.identityBaseUrl = storedIdentityUrl; - return; - } + if (urls.base) { + self.baseUrl = urls.base + '/api'; + self.identityBaseUrl = urls.base + '/identity'; + return; } - catch (e) { - console.log('Unable to set custom environment URLs:'); - console.log(e); + + if (urls.api && urls.identity) { + self.baseUrl = urls.api; + self.identityBaseUrl = urls.identity; + return; } // Desktop - //this.baseUrl = 'http://localhost:4000'; - //this.identityBaseUrl = 'http://localhost:33656'; + //self.baseUrl = 'http://localhost:4000'; + //self.identityBaseUrl = 'http://localhost:33656'; // Desktop HTTPS - //this.baseUrl = 'https://localhost:44377'; - //this.identityBaseUrl = 'https://localhost:44392'; + //self.baseUrl = 'https://localhost:44377'; + //self.identityBaseUrl = 'https://localhost:44392'; // Desktop external - //this.baseUrl = 'http://192.168.1.4:4000'; - //this.identityBaseUrl = 'http://192.168.1.4:33656'; + //self.baseUrl = 'http://192.168.1.4:4000'; + //self.identityBaseUrl = 'http://192.168.1.4:33656'; // Preview - //this.baseUrl = 'https://preview-api.bitwarden.com'; - //this.identityBaseUrl = 'https://preview-identity.bitwarden.com'; + //self.baseUrl = 'https://preview-api.bitwarden.com'; + //self.identityBaseUrl = 'https://preview-identity.bitwarden.com'; // Production - this.baseUrl = 'https://api.bitwarden.com'; - this.identityBaseUrl = 'https://identity.bitwarden.com'; + self.baseUrl = 'https://api.bitwarden.com'; + self.identityBaseUrl = 'https://identity.bitwarden.com'; }; // Auth APIs diff --git a/src/services/constantsService.js b/src/services/constantsService.js index 12c05d95..37a8e75a 100644 --- a/src/services/constantsService.js +++ b/src/services/constantsService.js @@ -1,9 +1,6 @@ function ConstantsService(i18nService) { return { - baseUrlKey: 'baseUrl', - webVaultUrlKey: 'webVaultUrl', - apiUrlKey: 'apiUrl', - identityUrlKey: 'identityUrl', + environmentUrlsKey: 'environmentUrls', disableGaKey: 'disableGa', disableAddLoginNotificationKey: 'disableAddLoginNotification', disableContextMenuItemKey: 'disableContextMenuItem', diff --git a/src/services/environmentService.js b/src/services/environmentService.js new file mode 100644 index 00000000..9fffdd35 --- /dev/null +++ b/src/services/environmentService.js @@ -0,0 +1,96 @@ +function EnvironmentService(constantsService, apiService) { + this.constantsService = constantsService; + this.apiService = apiService; + + this.baseUrl = null; + this.webVaultUrl = null; + this.apiUrl = null; + this.identityUrl = null; + + initEnvironmentService(); +} + +function initEnvironmentService() { + EnvironmentService.prototype.setUrlsFromStorage = function (callback) { + var self = this; + + chrome.storage.local.get(self.constantsService.environmentUrlsKey, function (urlsObj) { + var urls = urlsObj[self.constantsService.environmentUrlsKey] || { + base: null, + api: null, + identity: null, + webVault: null + }; + + self.baseUrl = urls.base; + if (self.baseUrl) { + self.apiService.setUrls({ + base: self.baseUrl + }); + callback(); + return; + } + + self.webVaultUrl = urls.webVault; + self.apiUrl = urls.api; + self.identityUrl = urls.identity; + + self.apiService.setUrls({ + api: self.apiUrl, + identity: self.identityUrl + }); + callback(); + return; + }); + }; + + EnvironmentService.prototype.setUrls = function (urls, callback) { + var self = this; + + urls.base = formatUrl(urls.base); + urls.webVault = formatUrl(urls.webVault); + urls.api = formatUrl(urls.api); + urls.identity = formatUrl(urls.identity); + + var urlsObj = {}; + urlsObj[self.constantsService.environmentUrlsKey] = { + base: urls.base, + api: urls.api, + identity: urls.identity, + webVault: urls.webVault + }; + + chrome.storage.local.set(urlsObj, function () { + self.baseUrl = urls.base; + self.webVaultUrl = urls.webVault; + self.apiUrl = urls.api; + self.identityUrl = urls.identity; + + if (self.baseUrl) { + self.apiService.setUrls({ + base: self.baseUrl + }); + } + else { + self.apiService.setUrls({ + api: self.apiUrl, + identity: self.identityUrl + }); + } + + callback(urls); + }); + }; + + function formatUrl(url) { + if (!url || url === '') { + return null; + } + + url = url.replace(/\/+$/g, ''); + if (!url.startsWith("http://") && !url.startsWith('https://')) { + url = 'https://' + url; + } + return url; + } +}