diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 65605050f7..0df78b318a 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -14,6 +14,7 @@ import WindowsBackground from './windows.background'; import ApiService from '../services/api.service'; import AppIdService from '../services/appId.service'; import AutofillService from '../services/autofill.service'; +import ChromeStorageService from '../services/chromeStorage.service'; import CipherService from '../services/cipher.service'; import CollectionService from '../services/collection.service'; import ConstantsService from '../services/constants.service'; @@ -30,7 +31,10 @@ import TotpService from '../services/totp.service'; import UserService from '../services/user.service'; import UtilsService from '../services/utils.service'; +import { StorageService } from '../services/abstractions/storage.service'; + export default class MainBackground { + storageService: StorageService; i18nService: any; utilsService: UtilsService; constantsService: ConstantsService; @@ -69,29 +73,31 @@ export default class MainBackground { constructor() { // Services + this.storageService = new ChromeStorageService(); this.utilsService = new UtilsService(); this.i18nService = i18nService(this.utilsService); this.constantsService = new ConstantsService(this.i18nService, this.utilsService); - this.cryptoService = new CryptoService(); - this.tokenService = new TokenService(); - this.appIdService = new AppIdService(); + this.cryptoService = new CryptoService(this.storageService, this.storageService); + this.tokenService = new TokenService(this.storageService); + this.appIdService = new AppIdService(this.storageService); this.apiService = new ApiService(this.tokenService, this.utilsService, (expired: boolean) => this.logout(expired)); - this.environmentService = new EnvironmentService(this.apiService); - this.userService = new UserService(this.tokenService); - this.settingsService = new SettingsService(this.userService); + this.environmentService = new EnvironmentService(this.apiService, this.storageService); + this.userService = new UserService(this.tokenService, this.storageService); + this.settingsService = new SettingsService(this.userService, this.storageService); this.cipherService = new CipherService(this.cryptoService, this.userService, this.settingsService, - this.apiService); + this.apiService, this.storageService); this.folderService = new FolderService(this.cryptoService, this.userService, this.i18nService, - this.apiService); - this.collectionService = new CollectionService(this.cryptoService, this.userService); + this.apiService, this.storageService); + this.collectionService = new CollectionService(this.cryptoService, this.userService, this.storageService); this.lockService = new LockService(this.cipherService, this.folderService, this.collectionService, - this.cryptoService, this.utilsService, () => this.setIcon(), () => this.refreshBadgeAndMenu()); + this.cryptoService, this.utilsService, this.storageService, + () => this.setIcon(), () => this.refreshBadgeAndMenu()); this.syncService = new SyncService(this.userService, this.apiService, this.settingsService, this.folderService, this.cipherService, this.cryptoService, this.collectionService, - (expired: boolean) => this.logout(expired)); - this.passwordGenerationService = new PasswordGenerationService(this.cryptoService); - this.totpService = new TotpService(); + this.storageService, (expired: boolean) => this.logout(expired)); + this.passwordGenerationService = new PasswordGenerationService(this.cryptoService, this.storageService); + this.totpService = new TotpService(this.storageService); this.autofillService = new AutofillService(this.cipherService, this.tokenService, this.totpService, this.utilsService); @@ -152,7 +158,7 @@ export default class MainBackground { return; } - const disabled = await this.utilsService.getObjFromStorage(ConstantsService.disableContextMenuItemKey); + const disabled = await this.storageService.get(ConstantsService.disableContextMenuItemKey); if (!disabled) { await this.buildContextMenu(); await this.contextMenuReady(tab, true); diff --git a/src/popup/app/services/background.service.ts b/src/popup/app/services/background.service.ts index 4f95f140a9..4e0aee42bb 100644 --- a/src/popup/app/services/background.service.ts +++ b/src/popup/app/services/background.service.ts @@ -1,4 +1,5 @@ import { CryptoService } from '../../../services/abstractions/crypto.service'; +import { StorageService } from '../../../services/abstractions/storage.service'; import { UtilsService } from '../../../services/abstractions/utils.service'; function getBackgroundService(service: string) { @@ -8,6 +9,7 @@ function getBackgroundService(service: string) { }; } +export const storageService = getBackgroundService('storageService'); export const tokenService = getBackgroundService('tokenService'); export const cryptoService = getBackgroundService('cryptoService'); export const userService = getBackgroundService('userService'); diff --git a/src/popup/app/services/services.module.ts b/src/popup/app/services/services.module.ts index 846a085918..79626cb24e 100644 --- a/src/popup/app/services/services.module.ts +++ b/src/popup/app/services/services.module.ts @@ -10,6 +10,7 @@ export default angular .service('validationService', ValidationService) .service('authService', AuthService) + .factory('storageService', backgroundServices.storageService) .factory('tokenService', backgroundServices.tokenService) .factory('cryptoService', backgroundServices.cryptoService) .factory('userService', backgroundServices.userService) diff --git a/src/popup/app/services/state.service.ts b/src/popup/app/services/state.service.ts index 43b66c7acb..2dc98ef077 100644 --- a/src/popup/app/services/state.service.ts +++ b/src/popup/app/services/state.service.ts @@ -1,16 +1,14 @@ -import { UtilsService } from '../../../services/abstractions/utils.service'; +import { StorageService } from '../../../services/abstractions/storage.service'; class StateService { private state: any = {}; - constructor(private utilsService: UtilsService, private constantsService: any) { + constructor(private storageService: StorageService, private constantsService: any) { } async init() { - const faviconsDisabled = await this.utilsService - .getObjFromStorage(this.constantsService.disableFaviconKey); - - this.saveState('faviconEnabled', !faviconsDisabled); + const iconsDisabled = await this.storageService.get(this.constantsService.disableFaviconKey); + this.saveState('faviconEnabled', !iconsDisabled); } saveState(key: string, data: any) { diff --git a/src/popup/app/settings/options.component.ts b/src/popup/app/settings/options.component.ts index e09614f0b7..653ea99221 100644 --- a/src/popup/app/settings/options.component.ts +++ b/src/popup/app/settings/options.component.ts @@ -1,4 +1,5 @@ import * as angular from 'angular'; +import { StorageService } from '../../../services/abstractions/storage.service'; import { UtilsService } from '../../../services/abstractions/utils.service'; import StateService from '../services/state.service'; import * as template from './options.component.html'; @@ -14,7 +15,7 @@ export class OptionsController { constructor(private i18nService: any, private $analytics: any, private constantsService: any, private utilsService: UtilsService, private totpService: any, private stateService: StateService, - private $timeout: ng.ITimeoutService) { + private storageService: StorageService, private $timeout: ng.ITimeoutService) { this.i18n = i18nService; $timeout(() => { @@ -25,22 +26,22 @@ export class OptionsController { } async loadSettings() { - this.enableAutoFillOnPageLoad = await this.utilsService.getObjFromStorage( + this.enableAutoFillOnPageLoad = await this.storageService.get( this.constantsService.enableAutoFillOnPageLoadKey); - const disableGa = await this.utilsService.getObjFromStorage( + const disableGa = await this.storageService.get( this.constantsService.disableGaKey); this.disableGa = disableGa || (this.utilsService.isFirefox() && disableGa === undefined); - this.disableAddLoginNotification = await this.utilsService.getObjFromStorage( + this.disableAddLoginNotification = await this.storageService.get( this.constantsService.disableAddLoginNotificationKey); - this.disableContextMenuItem = await this.utilsService.getObjFromStorage( + this.disableContextMenuItem = await this.storageService.get( this.constantsService.disableContextMenuItemKey); this.disableAutoTotpCopy = !await this.totpService.isAutoCopyEnabled(); - this.disableFavicon = await this.utilsService.getObjFromStorage( + this.disableFavicon = await this.storageService.get( this.constantsService.disableFaviconKey); } @@ -50,18 +51,18 @@ export class OptionsController { } updateGa() { - this.utilsService.saveObjToStorage(this.constantsService.disableGaKey, this.disableGa); + this.storageService.save(this.constantsService.disableGaKey, this.disableGa); this.callAnalytics('Analytics', !this.disableGa); } updateAddLoginNotification() { - this.utilsService.saveObjToStorage(this.constantsService.disableAddLoginNotificationKey, + this.storageService.save(this.constantsService.disableAddLoginNotificationKey, this.disableAddLoginNotification); this.callAnalytics('Add Login Notification', !this.disableAddLoginNotification); } updateDisableContextMenuItem() { - this.utilsService.saveObjToStorage(this.constantsService.disableContextMenuItemKey, + this.storageService.save(this.constantsService.disableContextMenuItemKey, this.disableContextMenuItem).then(() => { chrome.runtime.sendMessage({ command: 'bgUpdateContextMenu', @@ -71,18 +72,18 @@ export class OptionsController { } updateAutoTotpCopy() { - this.utilsService.saveObjToStorage(this.constantsService.disableAutoTotpCopyKey, this.disableAutoTotpCopy); + this.storageService.save(this.constantsService.disableAutoTotpCopyKey, this.disableAutoTotpCopy); this.callAnalytics('Auto Copy TOTP', !this.disableAutoTotpCopy); } updateAutoFillOnPageLoad() { - this.utilsService.saveObjToStorage(this.constantsService.enableAutoFillOnPageLoadKey, + this.storageService.save(this.constantsService.enableAutoFillOnPageLoadKey, this.enableAutoFillOnPageLoad); this.callAnalytics('Auto-fill Page Load', this.enableAutoFillOnPageLoad); } updateDisableFavicon() { - this.utilsService.saveObjToStorage(this.constantsService.disableFaviconKey, this.disableFavicon); + this.storageService.save(this.constantsService.disableFaviconKey, this.disableFavicon); this.stateService.saveState('faviconEnabled', !this.disableFavicon); this.callAnalytics('Favicon', !this.disableFavicon); } diff --git a/src/popup/app/settings/settings.component.ts b/src/popup/app/settings/settings.component.ts index f696f2438a..7a6dae9539 100644 --- a/src/popup/app/settings/settings.component.ts +++ b/src/popup/app/settings/settings.component.ts @@ -1,6 +1,7 @@ import * as angular from 'angular'; import { BrowserType } from '../../../enums/browserType.enum'; import { CryptoService } from '../../../services/abstractions/crypto.service'; +import { StorageService } from '../../../services/abstractions/storage.service'; import { UtilsService } from '../../../services/abstractions/utils.service'; import ConstantsService from '../../../services/constants.service'; @@ -28,7 +29,8 @@ export class SettingsController { constructor(private $state: any, private SweetAlert: any, private utilsService: UtilsService, private $analytics: any, private i18nService: any, private constantsService: ConstantsService, - private cryptoService: CryptoService, private lockService: any, private $timeout: ng.ITimeoutService) { + private cryptoService: CryptoService, private lockService: any, private storageService: StorageService, + private $timeout: ng.ITimeoutService) { this.i18n = i18nService; $timeout(() => { @@ -36,7 +38,7 @@ export class SettingsController { }, 500); this.showOnLocked = !utilsService.isFirefox() && !utilsService.isEdge(); - this.utilsService.getObjFromStorage(constantsService.lockOptionKey).then((lockOption: number) => { + this.storageService.get(constantsService.lockOptionKey).then((lockOption: number) => { if (lockOption != null) { let option = lockOption.toString(); if (option === '-2' && !this.showOnLocked) { @@ -51,7 +53,7 @@ export class SettingsController { changeLockOption() { const option = this.lockOption && this.lockOption !== '' ? parseInt(this.lockOption, 10) : null; - this.utilsService.saveObjToStorage(this.constantsService.lockOptionKey, option).then(() => { + this.storageService.save(this.constantsService.lockOptionKey, option).then(() => { return this.cryptoService.getKeyHash(); }).then((keyHash) => { if (keyHash) { diff --git a/src/services/abstractions/storage.service.ts b/src/services/abstractions/storage.service.ts new file mode 100644 index 0000000000..5d070d0a55 --- /dev/null +++ b/src/services/abstractions/storage.service.ts @@ -0,0 +1,5 @@ +export interface StorageService { + get(key: string): Promise; + save(key: string, obj: any): Promise; + remove(key: string): Promise; +} diff --git a/src/services/abstractions/utils.service.ts b/src/services/abstractions/utils.service.ts index e52eb44fec..348849c604 100644 --- a/src/services/abstractions/utils.service.ts +++ b/src/services/abstractions/utils.service.ts @@ -16,7 +16,4 @@ export interface UtilsService { inTab(theWindow: Window): boolean; inPopout(theWindow: Window): boolean; inPopup(theWindow: Window): boolean; - saveObjToStorage(key: string, obj: any): Promise; - removeFromStorage(key: string): Promise; - getObjFromStorage(key: string): Promise; } diff --git a/src/services/appId.service.ts b/src/services/appId.service.ts index d4e0dce5cb..c51dbed1df 100644 --- a/src/services/appId.service.ts +++ b/src/services/appId.service.ts @@ -1,31 +1,27 @@ import UtilsService from './utils.service'; +import { StorageService } from './abstractions/storage.service'; + export default class AppIdService { - static getAppId(): Promise { - return AppIdService.makeAndGetAppId('appId'); + constructor(private storageService: StorageService) { } - static getAnonymousAppId(): Promise { - return AppIdService.makeAndGetAppId('anonymousAppId'); + getAppId(): Promise { + return this.makeAndGetAppId('appId'); } - private static async makeAndGetAppId(key: string) { - const existingId = await UtilsService.getObjFromStorage(key); + getAnonymousAppId(): Promise { + return this.makeAndGetAppId('anonymousAppId'); + } + + private async makeAndGetAppId(key: string) { + const existingId = await this.storageService.get(key); if (existingId != null) { return existingId; } const guid = UtilsService.newGuid(); - await UtilsService.saveObjToStorage(key, guid); + await this.storageService.save(key, guid); return guid; } - - // TODO: remove these in favor of static methods - getAppId(): Promise { - return AppIdService.getAppId(); - } - - getAnonymousAppId(): Promise { - return AppIdService.getAnonymousAppId(); - } } diff --git a/src/services/chromeStorage.service.ts b/src/services/chromeStorage.service.ts new file mode 100644 index 0000000000..ade42fa5e7 --- /dev/null +++ b/src/services/chromeStorage.service.ts @@ -0,0 +1,31 @@ +import { StorageService as StorageServiceInterface } from './abstractions/storage.service'; + +export default class ChromeStorageService implements StorageServiceInterface { + get(key: string): Promise { + return new Promise((resolve) => { + chrome.storage.local.get(key, (obj: any) => { + if (obj && (typeof obj[key] !== 'undefined') && obj[key] !== null) { + resolve(obj[key] as T); + } else { + resolve(null); + } + }); + }); + } + + save(key: string, obj: any): Promise { + return new Promise((resolve) => { + chrome.storage.local.set({ [key]: obj }, () => { + resolve(); + }); + }); + } + + remove(key: string): Promise { + return new Promise((resolve) => { + chrome.storage.local.remove(key, () => { + resolve(); + }); + }); + } +} diff --git a/src/services/cipher.service.ts b/src/services/cipher.service.ts index 7b0d5d08b2..9159b06120 100644 --- a/src/services/cipher.service.ts +++ b/src/services/cipher.service.ts @@ -16,7 +16,8 @@ import ConstantsService from './constants.service'; import CryptoService from './crypto.service'; import SettingsService from './settings.service'; import UserService from './user.service'; -import UtilsService from './utils.service'; + +import { StorageService } from './abstractions/storage.service'; const Keys = { ciphersPrefix: 'ciphers_', @@ -68,7 +69,8 @@ export default class CipherService { decryptedCipherCache: any[]; constructor(private cryptoService: CryptoService, private userService: UserService, - private settingsService: SettingsService, private apiService: ApiService) { + private settingsService: SettingsService, private apiService: ApiService, + private storageService: StorageService) { } clearCache(): void { @@ -131,8 +133,8 @@ export default class CipherService { async get(id: string): Promise { const userId = await this.userService.getUserId(); - const localData = await UtilsService.getObjFromStorage(Keys.localData); - const ciphers = await UtilsService.getObjFromStorage<{ [id: string]: CipherData; }>( + const localData = await this.storageService.get(Keys.localData); + const ciphers = await this.storageService.get<{ [id: string]: CipherData; }>( Keys.ciphersPrefix + userId); if (ciphers == null || !ciphers.hasOwnProperty(id)) { return null; @@ -143,8 +145,8 @@ export default class CipherService { async getAll(): Promise { const userId = await this.userService.getUserId(); - const localData = await UtilsService.getObjFromStorage(Keys.localData); - const ciphers = await UtilsService.getObjFromStorage<{ [id: string]: CipherData; }>( + const localData = await this.storageService.get(Keys.localData); + const ciphers = await this.storageService.get<{ [id: string]: CipherData; }>( Keys.ciphersPrefix + userId); const response: Cipher[] = []; for (const id in ciphers) { @@ -243,7 +245,7 @@ export default class CipherService { } async updateLastUsedDate(id: string): Promise { - let ciphersLocalData = await UtilsService.getObjFromStorage(Keys.localData); + let ciphersLocalData = await this.storageService.get(Keys.localData); if (!ciphersLocalData) { ciphersLocalData = {}; } @@ -256,7 +258,7 @@ export default class CipherService { }; } - await UtilsService.saveObjToStorage(Keys.localData, ciphersLocalData); + await this.storageService.save(Keys.localData, ciphersLocalData); if (this.decryptedCipherCache == null) { return; @@ -276,12 +278,12 @@ export default class CipherService { return; } - let domains = await UtilsService.getObjFromStorage<{ [id: string]: any; }>(Keys.neverDomains); + let domains = await this.storageService.get<{ [id: string]: any; }>(Keys.neverDomains); if (!domains) { domains = {}; } domains[domain] = null; - await UtilsService.saveObjToStorage(Keys.neverDomains, domains); + await this.storageService.save(Keys.neverDomains, domains); } async saveWithServer(cipher: Cipher): Promise { @@ -339,7 +341,7 @@ export default class CipherService { async upsert(cipher: CipherData | CipherData[]): Promise { const userId = await this.userService.getUserId(); - let ciphers = await UtilsService.getObjFromStorage<{ [id: string]: CipherData; }>( + let ciphers = await this.storageService.get<{ [id: string]: CipherData; }>( Keys.ciphersPrefix + userId); if (ciphers == null) { ciphers = {}; @@ -354,24 +356,24 @@ export default class CipherService { }); } - await UtilsService.saveObjToStorage(Keys.ciphersPrefix + userId, ciphers); + await this.storageService.save(Keys.ciphersPrefix + userId, ciphers); this.decryptedCipherCache = null; } async replace(ciphers: { [id: string]: CipherData; }): Promise { const userId = await this.userService.getUserId(); - await UtilsService.saveObjToStorage(Keys.ciphersPrefix + userId, ciphers); + await this.storageService.save(Keys.ciphersPrefix + userId, ciphers); this.decryptedCipherCache = null; } async clear(userId: string): Promise { - await UtilsService.removeFromStorage(Keys.ciphersPrefix + userId); + await this.storageService.remove(Keys.ciphersPrefix + userId); this.decryptedCipherCache = null; } async delete(id: string | string[]): Promise { const userId = await this.userService.getUserId(); - const ciphers = await UtilsService.getObjFromStorage<{ [id: string]: CipherData; }>( + const ciphers = await this.storageService.get<{ [id: string]: CipherData; }>( Keys.ciphersPrefix + userId); if (ciphers == null) { return; @@ -386,7 +388,7 @@ export default class CipherService { }); } - await UtilsService.saveObjToStorage(Keys.ciphersPrefix + userId, ciphers); + await this.storageService.save(Keys.ciphersPrefix + userId, ciphers); this.decryptedCipherCache = null; } @@ -397,7 +399,7 @@ export default class CipherService { async deleteAttachment(id: string, attachmentId: string): Promise { const userId = await this.userService.getUserId(); - const ciphers = await UtilsService.getObjFromStorage<{ [id: string]: CipherData; }>( + const ciphers = await this.storageService.get<{ [id: string]: CipherData; }>( Keys.ciphersPrefix + userId); if (ciphers == null || !ciphers.hasOwnProperty(id) || ciphers[id].attachments == null) { @@ -410,7 +412,7 @@ export default class CipherService { } } - await UtilsService.saveObjToStorage(Keys.ciphersPrefix + userId, ciphers); + await this.storageService.save(Keys.ciphersPrefix + userId, ciphers); this.decryptedCipherCache = null; } diff --git a/src/services/collection.service.ts b/src/services/collection.service.ts index 14e23118be..fa1e1434e1 100644 --- a/src/services/collection.service.ts +++ b/src/services/collection.service.ts @@ -5,7 +5,8 @@ import { CollectionData } from '../models/data/collectionData'; import CryptoService from './crypto.service'; import UserService from './user.service'; -import UtilsService from './utils.service'; + +import { StorageService } from './abstractions/storage.service'; const Keys = { collectionsPrefix: 'collections_', @@ -14,7 +15,8 @@ const Keys = { export default class CollectionService { decryptedCollectionCache: any[]; - constructor(private cryptoService: CryptoService, private userService: UserService) { + constructor(private cryptoService: CryptoService, private userService: UserService, + private storageService: StorageService) { } clearCache(): void { @@ -23,7 +25,7 @@ export default class CollectionService { async get(id: string): Promise { const userId = await this.userService.getUserId(); - const collections = await UtilsService.getObjFromStorage<{ [id: string]: CollectionData; }>( + const collections = await this.storageService.get<{ [id: string]: CollectionData; }>( Keys.collectionsPrefix + userId); if (collections == null || !collections.hasOwnProperty(id)) { return null; @@ -34,7 +36,7 @@ export default class CollectionService { async getAll(): Promise { const userId = await this.userService.getUserId(); - const collections = await UtilsService.getObjFromStorage<{ [id: string]: CollectionData; }>( + const collections = await this.storageService.get<{ [id: string]: CollectionData; }>( Keys.collectionsPrefix + userId); const response: Collection[] = []; for (const id in collections) { @@ -71,7 +73,7 @@ export default class CollectionService { async upsert(collection: CollectionData | CollectionData[]): Promise { const userId = await this.userService.getUserId(); - let collections = await UtilsService.getObjFromStorage<{ [id: string]: CollectionData; }>( + let collections = await this.storageService.get<{ [id: string]: CollectionData; }>( Keys.collectionsPrefix + userId); if (collections == null) { collections = {}; @@ -86,24 +88,24 @@ export default class CollectionService { }); } - await UtilsService.saveObjToStorage(Keys.collectionsPrefix + userId, collections); + await this.storageService.save(Keys.collectionsPrefix + userId, collections); this.decryptedCollectionCache = null; } async replace(collections: { [id: string]: CollectionData; }): Promise { const userId = await this.userService.getUserId(); - await UtilsService.saveObjToStorage(Keys.collectionsPrefix + userId, collections); + await this.storageService.save(Keys.collectionsPrefix + userId, collections); this.decryptedCollectionCache = null; } async clear(userId: string): Promise { - await UtilsService.removeFromStorage(Keys.collectionsPrefix + userId); + await this.storageService.remove(Keys.collectionsPrefix + userId); this.decryptedCollectionCache = null; } async delete(id: string | string[]): Promise { const userId = await this.userService.getUserId(); - const collections = await UtilsService.getObjFromStorage<{ [id: string]: CollectionData; }>( + const collections = await this.storageService.get<{ [id: string]: CollectionData; }>( Keys.collectionsPrefix + userId); if (collections == null) { return; @@ -118,7 +120,7 @@ export default class CollectionService { }); } - await UtilsService.saveObjToStorage(Keys.collectionsPrefix + userId, collections); + await this.storageService.save(Keys.collectionsPrefix + userId, collections); this.decryptedCollectionCache = null; } } diff --git a/src/services/crypto.service.ts b/src/services/crypto.service.ts index 16c3c7497b..0a53466b89 100644 --- a/src/services/crypto.service.ts +++ b/src/services/crypto.service.ts @@ -11,6 +11,7 @@ import ConstantsService from './constants.service'; import UtilsService from './utils.service'; import { CryptoService as CryptoServiceInterface } from './abstractions/crypto.service'; +import { StorageService } from './abstractions/storage.service'; const Keys = { key: 'key', @@ -40,28 +41,31 @@ export default class CryptoService implements CryptoServiceInterface { private privateKey: ArrayBuffer; private orgKeys: Map; + constructor(private storageService: StorageService, private secureStorageService: StorageService) { + } + async setKey(key: SymmetricCryptoKey): Promise { this.key = key; - const option = await UtilsService.getObjFromStorage(ConstantsService.lockOptionKey); + const option = await this.storageService.get(ConstantsService.lockOptionKey); if (option != null) { // if we have a lock option set, we do not store the key return; } - return UtilsService.saveObjToStorage(Keys.key, key.keyB64); + return this.secureStorageService.save(Keys.key, key.keyB64); } setKeyHash(keyHash: string): Promise<{}> { this.keyHash = keyHash; - return UtilsService.saveObjToStorage(Keys.keyHash, keyHash); + return this.storageService.save(Keys.keyHash, keyHash); } async setEncKey(encKey: string): Promise<{}> { if (encKey == null) { return; } - await UtilsService.saveObjToStorage(Keys.encKey, encKey); + await this.storageService.save(Keys.encKey, encKey); this.encKey = null; } @@ -70,7 +74,7 @@ export default class CryptoService implements CryptoServiceInterface { return; } - await UtilsService.saveObjToStorage(Keys.encPrivateKey, encPrivateKey); + await this.storageService.save(Keys.encPrivateKey, encPrivateKey); this.privateKey = null; } @@ -80,7 +84,7 @@ export default class CryptoService implements CryptoServiceInterface { orgKeys[org.id] = org.key; }); - return UtilsService.saveObjToStorage(Keys.encOrgKeys, orgKeys); + return this.storageService.save(Keys.encOrgKeys, orgKeys); } async getKey(): Promise { @@ -88,12 +92,12 @@ export default class CryptoService implements CryptoServiceInterface { return this.key; } - const option = await UtilsService.getObjFromStorage(ConstantsService.lockOptionKey); + const option = await this.storageService.get(ConstantsService.lockOptionKey); if (option != null) { return null; } - const key = await UtilsService.getObjFromStorage(Keys.key); + const key = await this.secureStorageService.get(Keys.key); if (key) { this.key = new SymmetricCryptoKey(key, true); } @@ -106,7 +110,7 @@ export default class CryptoService implements CryptoServiceInterface { return Promise.resolve(this.keyHash); } - return UtilsService.getObjFromStorage(Keys.keyHash); + return this.storageService.get(Keys.keyHash); } async getEncKey(): Promise { @@ -114,7 +118,7 @@ export default class CryptoService implements CryptoServiceInterface { return this.encKey; } - const encKey = await UtilsService.getObjFromStorage(Keys.encKey); + const encKey = await this.storageService.get(Keys.encKey); if (encKey == null) { return null; } @@ -138,7 +142,7 @@ export default class CryptoService implements CryptoServiceInterface { return this.privateKey; } - const encPrivateKey = await UtilsService.getObjFromStorage(Keys.encPrivateKey); + const encPrivateKey = await this.storageService.get(Keys.encPrivateKey); if (encPrivateKey == null) { return null; } @@ -155,7 +159,7 @@ export default class CryptoService implements CryptoServiceInterface { } const self = this; - const encOrgKeys = await UtilsService.getObjFromStorage(Keys.encOrgKeys); + const encOrgKeys = await this.storageService.get(Keys.encOrgKeys); if (!encOrgKeys) { return null; } @@ -195,12 +199,12 @@ export default class CryptoService implements CryptoServiceInterface { clearKey(): Promise { this.key = this.legacyEtmKey = null; - return UtilsService.removeFromStorage(Keys.key); + return this.secureStorageService.remove(Keys.key); } clearKeyHash(): Promise { this.keyHash = null; - return UtilsService.removeFromStorage(Keys.keyHash); + return this.storageService.remove(Keys.keyHash); } clearEncKey(memoryOnly?: boolean): Promise { @@ -208,7 +212,7 @@ export default class CryptoService implements CryptoServiceInterface { if (memoryOnly) { return Promise.resolve(); } - return UtilsService.removeFromStorage(Keys.encKey); + return this.storageService.remove(Keys.encKey); } clearPrivateKey(memoryOnly?: boolean): Promise { @@ -216,7 +220,7 @@ export default class CryptoService implements CryptoServiceInterface { if (memoryOnly) { return Promise.resolve(); } - return UtilsService.removeFromStorage(Keys.encPrivateKey); + return this.storageService.remove(Keys.encPrivateKey); } clearOrgKeys(memoryOnly?: boolean): Promise { @@ -224,7 +228,7 @@ export default class CryptoService implements CryptoServiceInterface { if (memoryOnly) { return Promise.resolve(); } - return UtilsService.removeFromStorage(Keys.encOrgKeys); + return this.storageService.remove(Keys.encOrgKeys); } clearKeys(): Promise { @@ -239,7 +243,7 @@ export default class CryptoService implements CryptoServiceInterface { async toggleKey(): Promise { const key = await this.getKey(); - const option = await UtilsService.getObjFromStorage(ConstantsService.lockOptionKey); + const option = await this.storageService.get(ConstantsService.lockOptionKey); if (option != null || option === 0) { // if we have a lock option set, clear the key await this.clearKey(); diff --git a/src/services/environment.service.ts b/src/services/environment.service.ts index 098a67f749..797d9d5b8d 100644 --- a/src/services/environment.service.ts +++ b/src/services/environment.service.ts @@ -1,6 +1,7 @@ import ApiService from './api.service'; import ConstantsService from './constants.service'; -import UtilsService from './utils.service'; + +import { StorageService } from './abstractions/storage.service'; import EnvironmentUrls from '../models/domain/environmentUrls'; @@ -11,11 +12,11 @@ export default class EnvironmentService { identityUrl: string; iconsUrl: string; - constructor(private apiService: ApiService) { + constructor(private apiService: ApiService, private storageService: StorageService) { } async setUrlsFromStorage(): Promise { - const urlsObj: any = await UtilsService.getObjFromStorage(ConstantsService.environmentUrlsKey); + const urlsObj: any = await this.storageService.get(ConstantsService.environmentUrlsKey); const urls = urlsObj || { base: null, api: null, @@ -46,7 +47,7 @@ export default class EnvironmentService { urls.identity = this.formatUrl(urls.identity); urls.icons = this.formatUrl(urls.icons); - await UtilsService.saveObjToStorage(ConstantsService.environmentUrlsKey, { + await this.storageService.save(ConstantsService.environmentUrlsKey, { base: urls.base, api: urls.api, identity: urls.identity, diff --git a/src/services/folder.service.ts b/src/services/folder.service.ts index 3337c1b0bc..a0af57f5ea 100644 --- a/src/services/folder.service.ts +++ b/src/services/folder.service.ts @@ -9,7 +9,8 @@ import { FolderResponse } from '../models/response/folderResponse'; import ApiService from './api.service'; import CryptoService from './crypto.service'; import UserService from './user.service'; -import UtilsService from './utils.service'; + +import { StorageService } from './abstractions/storage.service'; const Keys = { foldersPrefix: 'folders_', @@ -19,7 +20,7 @@ export default class FolderService { decryptedFolderCache: any[]; constructor(private cryptoService: CryptoService, private userService: UserService, - private i18nService: any, private apiService: ApiService) { + private i18nService: any, private apiService: ApiService, private storageService: StorageService) { } clearCache(): void { @@ -35,7 +36,7 @@ export default class FolderService { async get(id: string): Promise { const userId = await this.userService.getUserId(); - const folders = await UtilsService.getObjFromStorage<{ [id: string]: FolderData; }>( + const folders = await this.storageService.get<{ [id: string]: FolderData; }>( Keys.foldersPrefix + userId); if (folders == null || !folders.hasOwnProperty(id)) { return null; @@ -46,7 +47,7 @@ export default class FolderService { async getAll(): Promise { const userId = await this.userService.getUserId(); - const folders = await UtilsService.getObjFromStorage<{ [id: string]: FolderData; }>( + const folders = await this.storageService.get<{ [id: string]: FolderData; }>( Keys.foldersPrefix + userId); const response: Folder[] = []; for (const id in folders) { @@ -103,7 +104,7 @@ export default class FolderService { async upsert(folder: FolderData | FolderData[]): Promise { const userId = await this.userService.getUserId(); - let folders = await UtilsService.getObjFromStorage<{ [id: string]: FolderData; }>( + let folders = await this.storageService.get<{ [id: string]: FolderData; }>( Keys.foldersPrefix + userId); if (folders == null) { folders = {}; @@ -118,24 +119,24 @@ export default class FolderService { }); } - await UtilsService.saveObjToStorage(Keys.foldersPrefix + userId, folders); + await this.storageService.save(Keys.foldersPrefix + userId, folders); this.decryptedFolderCache = null; } async replace(folders: { [id: string]: FolderData; }): Promise { const userId = await this.userService.getUserId(); - await UtilsService.saveObjToStorage(Keys.foldersPrefix + userId, folders); + await this.storageService.save(Keys.foldersPrefix + userId, folders); this.decryptedFolderCache = null; } async clear(userId: string): Promise { - await UtilsService.removeFromStorage(Keys.foldersPrefix + userId); + await this.storageService.remove(Keys.foldersPrefix + userId); this.decryptedFolderCache = null; } async delete(id: string | string[]): Promise { const userId = await this.userService.getUserId(); - const folders = await UtilsService.getObjFromStorage<{ [id: string]: FolderData; }>( + const folders = await this.storageService.get<{ [id: string]: FolderData; }>( Keys.foldersPrefix + userId); if (folders == null) { return; @@ -150,7 +151,7 @@ export default class FolderService { }); } - await UtilsService.saveObjToStorage(Keys.foldersPrefix + userId, folders); + await this.storageService.save(Keys.foldersPrefix + userId, folders); this.decryptedFolderCache = null; } diff --git a/src/services/lock.service.ts b/src/services/lock.service.ts index bc58aacbab..b528b2c136 100644 --- a/src/services/lock.service.ts +++ b/src/services/lock.service.ts @@ -5,10 +5,13 @@ import CryptoService from './crypto.service'; import FolderService from './folder.service'; import UtilsService from './utils.service'; +import { StorageService } from './abstractions/storage.service'; + export default class LockService { constructor(private cipherService: CipherService, private folderService: FolderService, private collectionService: CollectionService, private cryptoService: CryptoService, - private utilsService: UtilsService, private setIcon: Function, private refreshBadgeAndMenu: Function) { + private utilsService: UtilsService, private storageService: StorageService, + private setIcon: Function, private refreshBadgeAndMenu: Function) { this.checkLock(); setInterval(() => this.checkLock(), 10 * 1000); // check every 10 seconds @@ -16,7 +19,7 @@ export default class LockService { if ((window as any).chrome.idle && (window as any).chrome.idle.onStateChanged) { (window as any).chrome.idle.onStateChanged.addListener(async (newState: string) => { if (newState === 'locked') { - const lockOption = await UtilsService.getObjFromStorage(ConstantsService.lockOptionKey); + const lockOption = await this.storageService.get(ConstantsService.lockOptionKey); if (lockOption === -2) { self.lock(); } @@ -42,12 +45,12 @@ export default class LockService { return; } - const lockOption = await UtilsService.getObjFromStorage(ConstantsService.lockOptionKey); + const lockOption = await this.storageService.get(ConstantsService.lockOptionKey); if (lockOption == null || lockOption < 0) { return; } - const lastActive = await UtilsService.getObjFromStorage(ConstantsService.lastActiveKey); + const lastActive = await this.storageService.get(ConstantsService.lastActiveKey); if (lastActive == null) { return; } diff --git a/src/services/passwordGeneration.service.ts b/src/services/passwordGeneration.service.ts index 4e52438d46..23f1ad9c91 100644 --- a/src/services/passwordGeneration.service.ts +++ b/src/services/passwordGeneration.service.ts @@ -4,6 +4,8 @@ import PasswordHistory from '../models/domain/passwordHistory'; import CryptoService from './crypto.service'; import UtilsService from './utils.service'; +import { StorageService } from './abstractions/storage.service'; + const DefaultOptions = { length: 14, ambiguous: false, @@ -145,8 +147,8 @@ export default class PasswordGenerationService { optionsCache: any; history: PasswordHistory[] = []; - constructor(private cryptoService: CryptoService) { - UtilsService.getObjFromStorage(Keys.history).then((encrypted) => { + constructor(private cryptoService: CryptoService, private storageService: StorageService) { + storageService.get(Keys.history).then((encrypted) => { return this.decryptHistory(encrypted); }).then((history) => { this.history = history; @@ -159,7 +161,7 @@ export default class PasswordGenerationService { async getOptions() { if (this.optionsCache == null) { - const options = await UtilsService.getObjFromStorage(Keys.options); + const options = await this.storageService.get(Keys.options); if (options == null) { this.optionsCache = DefaultOptions; } else { @@ -171,7 +173,7 @@ export default class PasswordGenerationService { } async saveOptions(options: any) { - await UtilsService.saveObjToStorage(Keys.options, options); + await this.storageService.save(Keys.options, options); this.optionsCache = options; } @@ -193,12 +195,12 @@ export default class PasswordGenerationService { } const newHistory = await this.encryptHistory(); - return await UtilsService.saveObjToStorage(Keys.history, newHistory); + return await this.storageService.save(Keys.history, newHistory); } async clear(): Promise { this.history = []; - return await UtilsService.removeFromStorage(Keys.history); + return await this.storageService.remove(Keys.history); } private async encryptHistory(): Promise { diff --git a/src/services/settings.service.ts b/src/services/settings.service.ts index 25d598f83c..4980849467 100644 --- a/src/services/settings.service.ts +++ b/src/services/settings.service.ts @@ -1,5 +1,6 @@ import UserService from './user.service'; -import UtilsService from './utils.service'; + +import { StorageService } from './abstractions/storage.service'; const Keys = { settingsPrefix: 'settings_', @@ -9,7 +10,7 @@ const Keys = { export default class SettingsService { private settingsCache: any; - constructor(private userService: UserService) { + constructor(private userService: UserService, private storageService: StorageService) { } clearCache(): void { @@ -25,7 +26,7 @@ export default class SettingsService { } async clear(userId: string): Promise { - await UtilsService.removeFromStorage(Keys.settingsPrefix + userId); + await this.storageService.remove(Keys.settingsPrefix + userId); this.settingsCache = null; } @@ -34,7 +35,7 @@ export default class SettingsService { private async getSettings(): Promise { if (this.settingsCache == null) { const userId = await this.userService.getUserId(); - this.settingsCache = UtilsService.getObjFromStorage(Keys.settingsPrefix + userId); + this.settingsCache = this.storageService.get(Keys.settingsPrefix + userId); } return this.settingsCache; } @@ -55,7 +56,7 @@ export default class SettingsService { } settings[key] = value; - await UtilsService.saveObjToStorage(Keys.settingsPrefix + userId, settings); + await this.storageService.save(Keys.settingsPrefix + userId, settings); this.settingsCache = settings; } } diff --git a/src/services/sync.service.ts b/src/services/sync.service.ts index a28c401f19..5789990e36 100644 --- a/src/services/sync.service.ts +++ b/src/services/sync.service.ts @@ -16,7 +16,8 @@ import CryptoService from './crypto.service'; import FolderService from './folder.service'; import SettingsService from './settings.service'; import UserService from './user.service'; -import UtilsService from './utils.service'; + +import { StorageService } from './abstractions/storage.service'; const Keys = { lastSyncPrefix: 'lastSync_', @@ -28,12 +29,13 @@ export default class SyncService { constructor(private userService: UserService, private apiService: ApiService, private settingsService: SettingsService, private folderService: FolderService, private cipherService: CipherService, private cryptoService: CryptoService, - private collectionService: CollectionService, private logoutCallback: Function) { + private collectionService: CollectionService, private storageService: StorageService, + private logoutCallback: Function) { } async getLastSync() { const userId = await this.userService.getUserId(); - const lastSync = await UtilsService.getObjFromStorage(Keys.lastSyncPrefix + userId); + const lastSync = await this.storageService.get(Keys.lastSyncPrefix + userId); if (lastSync) { return new Date(lastSync); } @@ -43,7 +45,7 @@ export default class SyncService { async setLastSync(date: Date) { const userId = await this.userService.getUserId(); - await UtilsService.saveObjToStorage(Keys.lastSyncPrefix + userId, date.toJSON()); + await this.storageService.save(Keys.lastSyncPrefix + userId, date.toJSON()); } syncStarted() { diff --git a/src/services/token.service.ts b/src/services/token.service.ts index 3ebaa239be..527305b2f3 100644 --- a/src/services/token.service.ts +++ b/src/services/token.service.ts @@ -1,6 +1,8 @@ import ConstantsService from './constants.service'; import UtilsService from './utils.service'; +import { StorageService } from './abstractions/storage.service'; + const Keys = { accessToken: 'accessToken', refreshToken: 'refreshToken', @@ -12,6 +14,9 @@ export default class TokenService { decodedToken: any; refreshToken: string; + constructor(private storageService: StorageService) { + } + setTokens(accessToken: string, refreshToken: string): Promise { return Promise.all([ this.setToken(accessToken), @@ -22,7 +27,7 @@ export default class TokenService { setToken(token: string): Promise { this.token = token; this.decodedToken = null; - return UtilsService.saveObjToStorage(Keys.accessToken, token); + return this.storageService.save(Keys.accessToken, token); } async getToken(): Promise { @@ -30,13 +35,13 @@ export default class TokenService { return this.token; } - this.token = await UtilsService.getObjFromStorage(Keys.accessToken); + this.token = await this.storageService.get(Keys.accessToken); return this.token; } setRefreshToken(refreshToken: string): Promise { this.refreshToken = refreshToken; - return UtilsService.saveObjToStorage(Keys.refreshToken, refreshToken); + return this.storageService.save(Keys.refreshToken, refreshToken); } async getRefreshToken(): Promise { @@ -44,20 +49,20 @@ export default class TokenService { return this.refreshToken; } - this.refreshToken = await UtilsService.getObjFromStorage(Keys.refreshToken); + this.refreshToken = await this.storageService.get(Keys.refreshToken); return this.refreshToken; } setTwoFactorToken(token: string, email: string): Promise { - return UtilsService.saveObjToStorage(Keys.twoFactorTokenPrefix + email, token); + return this.storageService.save(Keys.twoFactorTokenPrefix + email, token); } getTwoFactorToken(email: string): Promise { - return UtilsService.getObjFromStorage(Keys.twoFactorTokenPrefix + email); + return this.storageService.get(Keys.twoFactorTokenPrefix + email); } clearTwoFactorToken(email: string): Promise { - return UtilsService.removeFromStorage(Keys.twoFactorTokenPrefix + email); + return this.storageService.remove(Keys.twoFactorTokenPrefix + email); } clearToken(): Promise { @@ -66,8 +71,8 @@ export default class TokenService { this.refreshToken = null; return Promise.all([ - UtilsService.removeFromStorage(Keys.accessToken), - UtilsService.removeFromStorage(Keys.refreshToken), + this.storageService.remove(Keys.accessToken), + this.storageService.remove(Keys.refreshToken), ]); } diff --git a/src/services/totp.service.ts b/src/services/totp.service.ts index ae4d4ec57a..e1a00b937e 100644 --- a/src/services/totp.service.ts +++ b/src/services/totp.service.ts @@ -1,5 +1,6 @@ import ConstantsService from './constants.service'; -import UtilsService from './utils.service'; + +import { StorageService } from './abstractions/storage.service'; const b32Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; @@ -9,6 +10,9 @@ const TotpAlgorithm = { }; export default class TotpService { + constructor(private storageService: StorageService) { + } + async getCode(keyb32: string): Promise { const epoch = Math.round(new Date().getTime() / 1000.0); const timeHex = this.leftpad(this.dec2hex(Math.floor(epoch / 30)), 16, '0'); @@ -32,7 +36,7 @@ export default class TotpService { } async isAutoCopyEnabled(): Promise { - return !(await UtilsService.getObjFromStorage(ConstantsService.disableAutoTotpCopyKey)); + return !(await this.storageService.get(ConstantsService.disableAutoTotpCopyKey)); } // Helpers diff --git a/src/services/user.service.ts b/src/services/user.service.ts index caa56c0d6f..3a5f80a86a 100644 --- a/src/services/user.service.ts +++ b/src/services/user.service.ts @@ -1,5 +1,6 @@ import TokenService from './token.service'; -import UtilsService from './utils.service'; + +import { StorageService } from './abstractions/storage.service'; const Keys = { userId: 'userId', @@ -12,7 +13,7 @@ export default class UserService { email: string; stamp: string; - constructor(private tokenService: TokenService) { + constructor(private tokenService: TokenService, private storageService: StorageService) { } setUserIdAndEmail(userId: string, email: string): Promise { @@ -20,14 +21,14 @@ export default class UserService { this.userId = userId; return Promise.all([ - UtilsService.saveObjToStorage(Keys.userEmail, email), - UtilsService.saveObjToStorage(Keys.userId, userId), + this.storageService.save(Keys.userEmail, email), + this.storageService.save(Keys.userId, userId), ]); } setSecurityStamp(stamp: string): Promise { this.stamp = stamp; - return UtilsService.saveObjToStorage(Keys.stamp, stamp); + return this.storageService.save(Keys.stamp, stamp); } async getUserId(): Promise { @@ -35,7 +36,7 @@ export default class UserService { return this.userId; } - this.userId = await UtilsService.getObjFromStorage(Keys.userId); + this.userId = await this.storageService.get(Keys.userId); return this.userId; } @@ -44,7 +45,7 @@ export default class UserService { return this.email; } - this.email = await UtilsService.getObjFromStorage(Keys.userEmail); + this.email = await this.storageService.get(Keys.userEmail); return this.email; } @@ -53,15 +54,15 @@ export default class UserService { return this.stamp; } - this.stamp = await UtilsService.getObjFromStorage(Keys.stamp); + this.stamp = await this.storageService.get(Keys.stamp); return this.stamp; } async clear(): Promise { await Promise.all([ - UtilsService.removeFromStorage(Keys.userId), - UtilsService.removeFromStorage(Keys.userEmail), - UtilsService.removeFromStorage(Keys.stamp), + this.storageService.remove(Keys.userId), + this.storageService.remove(Keys.userEmail), + this.storageService.remove(Keys.stamp), ]); this.userId = this.email = this.stamp = null; diff --git a/src/services/utils.service.ts b/src/services/utils.service.ts index b2230de2b9..53e5df7cfd 100644 --- a/src/services/utils.service.ts +++ b/src/services/utils.service.ts @@ -136,34 +136,6 @@ export default class UtilsService implements UtilsServiceInterface { return decodeURIComponent(escape(encodedString)); } - static saveObjToStorage(key: string, obj: any) { - return new Promise((resolve) => { - chrome.storage.local.set({ [key]: obj }, () => { - resolve(); - }); - }); - } - - static removeFromStorage(key: string) { - return new Promise((resolve) => { - chrome.storage.local.remove(key, () => { - resolve(); - }); - }); - } - - static getObjFromStorage(key: string): Promise { - return new Promise((resolve) => { - chrome.storage.local.get(key, (obj: any) => { - if (obj && (typeof obj[key] !== 'undefined') && obj[key] !== null) { - resolve(obj[key] as T); - } else { - resolve(null); - } - }); - }); - } - static getDomain(uriString: string): string { if (uriString == null) { return null; @@ -392,16 +364,4 @@ export default class UtilsService implements UtilsServiceInterface { return theWindow.location.search === '' || theWindow.location.search.indexOf('uilocation=') === -1 || theWindow.location.search.indexOf('uilocation=popup') > -1; } - - saveObjToStorage(key: string, obj: any): Promise { - return UtilsService.saveObjToStorage(key, obj); - } - - removeFromStorage(key: string): Promise { - return UtilsService.removeFromStorage(key); - } - - getObjFromStorage(key: string): Promise { - return UtilsService.getObjFromStorage(key); - } }