1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

[Account Switching] Base changes for account switching (#2250)

* Pull in jslib

* Create new state models

* Create browser specific stateService

* Remove registration deprecated services, register stateService

* Replace usage of deprecated services (user, constants)

* Add missing properties to BrowserGroupingsComponentState

* Remove StorageService from initFactory

* Clear the correct state

* Add null check when restoring send-grouping state

* add remember email

* Initialize stateservice in services.module

* Fix 'lock now' not working

* Comment to remove setting defaults on install

* Pull jslib

* Remove setting defaults on install

* Bump jslib

* Pass the current userId to services when logging out

* Bump jslib

* Override vaultTimeout default on account addition

* Pull latest jslib

* Retrieve vaultTimeout from stateService

* Record activity per Account

* Add userId to logout and add fallback if not present

* Register AccountFactory

* Pass userId in messages

* Base changes for account switching di fixes (#2280)

* [bug] Null checks on Account init

* [bug] Use same stateService instance for all operations

We override the stateService in browser, but currently don't pull the background service into popup and allow jslib to create its own instance of the base StateService for jslib services.
This causes a split in in memory state between the three isntances that results in many errors, namely locking not working.

* [chore] Update jslib

* Pull in jslib

* Pull in jslib

* Pull in latest jslib to multiple stateservice inits

* Check vault states before executing processReload

* Adjust iterator

* Update native messaging to include the userId (#2290)

* Re-Add UserVerificationService

* Fix email not being remembered by base component

* Improve readability of reloadProcess

* Removed unneeded null check

* Fix constructor dependency (stateService)

* Added missing await

* Simplify dependency registration

* Fixed typos

* Reverted back to simple loop

* Use vaultTimeoutService to retrieve Timeout

Co-authored-by: Addison Beck <abeck@bitwarden.com>
Co-authored-by: Oscar Hinton <oscar@oscarhinton.com>
This commit is contained in:
Daniel James Smith
2022-01-27 22:22:51 +01:00
committed by GitHub
parent ade2a96239
commit bd770c90ed
41 changed files with 663 additions and 527 deletions

2
jslib

Submodule jslib updated: 8fc3cf50d2...4722a287ec

View File

@@ -1,8 +1,7 @@
import { NotificationsService } from "jslib-common/abstractions/notifications.service"; import { NotificationsService } from "jslib-common/abstractions/notifications.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
import { ConstantsService } from "jslib-common/services/constants.service"; import { StateService } from "../services/abstractions/state.service";
const IdleInterval = 60 * 5; // 5 minutes const IdleInterval = 60 * 5; // 5 minutes
@@ -13,7 +12,7 @@ export default class IdleBackground {
constructor( constructor(
private vaultTimeoutService: VaultTimeoutService, private vaultTimeoutService: VaultTimeoutService,
private storageService: StorageService, private stateService: StateService,
private notificationsService: NotificationsService private notificationsService: NotificationsService
) { ) {
this.idle = chrome.idle || (browser != null ? browser.idle : null); this.idle = chrome.idle || (browser != null ? browser.idle : null);
@@ -42,12 +41,10 @@ export default class IdleBackground {
this.idle.onStateChanged.addListener(async (newState: string) => { this.idle.onStateChanged.addListener(async (newState: string) => {
if (newState === "locked") { if (newState === "locked") {
// If the screen is locked or the screensaver activates // If the screen is locked or the screensaver activates
const timeout = await this.storageService.get<number>(ConstantsService.vaultTimeoutKey); const timeout = await this.stateService.getVaultTimeout();
if (timeout === -2) { if (timeout === -2) {
// On System Lock vault timeout option // On System Lock vault timeout option
const action = await this.storageService.get<string>( const action = await this.stateService.getVaultTimeoutAction();
ConstantsService.vaultTimeoutActionKey
);
if (action === "logOut") { if (action === "logOut") {
await this.vaultTimeoutService.logOut(); await this.vaultTimeoutService.logOut();
} else { } else {

View File

@@ -1,6 +1,7 @@
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType"; import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
import { CipherType } from "jslib-common/enums/cipherType"; import { CipherType } from "jslib-common/enums/cipherType";
import { AccountFactory } from "jslib-common/models/domain/account";
import { CipherView } from "jslib-common/models/view/cipherView"; import { CipherView } from "jslib-common/models/view/cipherView";
import { ApiService } from "jslib-common/services/api.service"; import { ApiService } from "jslib-common/services/api.service";
@@ -10,7 +11,6 @@ import { AuthService } from "jslib-common/services/auth.service";
import { CipherService } from "jslib-common/services/cipher.service"; import { CipherService } from "jslib-common/services/cipher.service";
import { CollectionService } from "jslib-common/services/collection.service"; import { CollectionService } from "jslib-common/services/collection.service";
import { ConsoleLogService } from "jslib-common/services/consoleLog.service"; import { ConsoleLogService } from "jslib-common/services/consoleLog.service";
import { ConstantsService } from "jslib-common/services/constants.service";
import { ContainerService } from "jslib-common/services/container.service"; import { ContainerService } from "jslib-common/services/container.service";
import { EnvironmentService } from "jslib-common/services/environment.service"; import { EnvironmentService } from "jslib-common/services/environment.service";
import { EventService } from "jslib-common/services/event.service"; import { EventService } from "jslib-common/services/event.service";
@@ -19,17 +19,18 @@ import { FileUploadService } from "jslib-common/services/fileUpload.service";
import { FolderService } from "jslib-common/services/folder.service"; import { FolderService } from "jslib-common/services/folder.service";
import { KeyConnectorService } from "jslib-common/services/keyConnector.service"; import { KeyConnectorService } from "jslib-common/services/keyConnector.service";
import { NotificationsService } from "jslib-common/services/notifications.service"; import { NotificationsService } from "jslib-common/services/notifications.service";
import { OrganizationService } from "jslib-common/services/organization.service";
import { PasswordGenerationService } from "jslib-common/services/passwordGeneration.service"; import { PasswordGenerationService } from "jslib-common/services/passwordGeneration.service";
import { PolicyService } from "jslib-common/services/policy.service"; import { PolicyService } from "jslib-common/services/policy.service";
import { ProviderService } from "jslib-common/services/provider.service";
import { SearchService } from "jslib-common/services/search.service"; import { SearchService } from "jslib-common/services/search.service";
import { SendService } from "jslib-common/services/send.service"; import { SendService } from "jslib-common/services/send.service";
import { SettingsService } from "jslib-common/services/settings.service"; import { SettingsService } from "jslib-common/services/settings.service";
import { StateService } from "jslib-common/services/state.service"; import { StateMigrationService } from "jslib-common/services/stateMigration.service";
import { SyncService } from "jslib-common/services/sync.service"; import { SyncService } from "jslib-common/services/sync.service";
import { SystemService } from "jslib-common/services/system.service"; import { SystemService } from "jslib-common/services/system.service";
import { TokenService } from "jslib-common/services/token.service"; import { TokenService } from "jslib-common/services/token.service";
import { TotpService } from "jslib-common/services/totp.service"; import { TotpService } from "jslib-common/services/totp.service";
import { UserService } from "jslib-common/services/user.service";
import { UserVerificationService } from "jslib-common/services/userVerification.service"; import { UserVerificationService } from "jslib-common/services/userVerification.service";
import { WebCryptoFunctionService } from "jslib-common/services/webCryptoFunction.service"; import { WebCryptoFunctionService } from "jslib-common/services/webCryptoFunction.service";
@@ -51,19 +52,19 @@ import { KeyConnectorService as KeyConnectorServiceAbstraction } from "jslib-com
import { LogService as LogServiceAbstraction } from "jslib-common/abstractions/log.service"; import { LogService as LogServiceAbstraction } from "jslib-common/abstractions/log.service";
import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service"; import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service";
import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service"; import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service";
import { OrganizationService as OrganizationServiceAbstraction } from "jslib-common/abstractions/organization.service";
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "jslib-common/abstractions/passwordGeneration.service"; import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService as PolicyServiceAbstraction } from "jslib-common/abstractions/policy.service"; import { PolicyService as PolicyServiceAbstraction } from "jslib-common/abstractions/policy.service";
import { ProviderService as ProviderServiceAbstraction } from "jslib-common/abstractions/provider.service";
import { SearchService as SearchServiceAbstraction } from "jslib-common/abstractions/search.service"; import { SearchService as SearchServiceAbstraction } from "jslib-common/abstractions/search.service";
import { SendService as SendServiceAbstraction } from "jslib-common/abstractions/send.service"; import { SendService as SendServiceAbstraction } from "jslib-common/abstractions/send.service";
import { SettingsService as SettingsServiceAbstraction } from "jslib-common/abstractions/settings.service"; import { SettingsService as SettingsServiceAbstraction } from "jslib-common/abstractions/settings.service";
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service";
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service"; import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
import { SyncService as SyncServiceAbstraction } from "jslib-common/abstractions/sync.service"; import { SyncService as SyncServiceAbstraction } from "jslib-common/abstractions/sync.service";
import { SystemService as SystemServiceAbstraction } from "jslib-common/abstractions/system.service"; import { SystemService as SystemServiceAbstraction } from "jslib-common/abstractions/system.service";
import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.service"; import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.service";
import { TotpService as TotpServiceAbstraction } from "jslib-common/abstractions/totp.service"; import { TotpService as TotpServiceAbstraction } from "jslib-common/abstractions/totp.service";
import { UserService as UserServiceAbstraction } from "jslib-common/abstractions/user.service";
import { UserVerificationService as UserVerificationServiceAbstraction } from "jslib-common/abstractions/userVerification.service"; import { UserVerificationService as UserVerificationServiceAbstraction } from "jslib-common/abstractions/userVerification.service";
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service"; import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service";
@@ -82,6 +83,8 @@ import TabsBackground from "./tabs.background";
import WebRequestBackground from "./webRequest.background"; import WebRequestBackground from "./webRequest.background";
import WindowsBackground from "./windows.background"; import WindowsBackground from "./windows.background";
import { StateService as StateServiceAbstraction } from "../services/abstractions/state.service";
import { PopupUtilsService } from "../popup/services/popup-utils.service"; import { PopupUtilsService } from "../popup/services/popup-utils.service";
import AutofillService from "../services/autofill.service"; import AutofillService from "../services/autofill.service";
import { BrowserCryptoService } from "../services/browserCrypto.service"; import { BrowserCryptoService } from "../services/browserCrypto.service";
@@ -89,15 +92,17 @@ import BrowserMessagingService from "../services/browserMessaging.service";
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service"; import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
import BrowserStorageService from "../services/browserStorage.service"; import BrowserStorageService from "../services/browserStorage.service";
import I18nService from "../services/i18n.service"; import I18nService from "../services/i18n.service";
import { StateService } from "../services/state.service";
import VaultTimeoutService from "../services/vaultTimeout.service"; import VaultTimeoutService from "../services/vaultTimeout.service";
import { Account } from "../models/account";
export default class MainBackground { export default class MainBackground {
messagingService: MessagingServiceAbstraction; messagingService: MessagingServiceAbstraction;
storageService: StorageServiceAbstraction; storageService: StorageServiceAbstraction;
secureStorageService: StorageServiceAbstraction; secureStorageService: StorageServiceAbstraction;
i18nService: I18nServiceAbstraction; i18nService: I18nServiceAbstraction;
platformUtilsService: PlatformUtilsServiceAbstraction; platformUtilsService: PlatformUtilsServiceAbstraction;
constantsService: ConstantsService;
logService: LogServiceAbstraction; logService: LogServiceAbstraction;
cryptoService: CryptoServiceAbstraction; cryptoService: CryptoServiceAbstraction;
cryptoFunctionService: CryptoFunctionServiceAbstraction; cryptoFunctionService: CryptoFunctionServiceAbstraction;
@@ -105,7 +110,6 @@ export default class MainBackground {
appIdService: AppIdServiceAbstraction; appIdService: AppIdServiceAbstraction;
apiService: ApiServiceAbstraction; apiService: ApiServiceAbstraction;
environmentService: EnvironmentServiceAbstraction; environmentService: EnvironmentServiceAbstraction;
userService: UserServiceAbstraction;
settingsService: SettingsServiceAbstraction; settingsService: SettingsServiceAbstraction;
cipherService: CipherServiceAbstraction; cipherService: CipherServiceAbstraction;
folderService: FolderServiceAbstraction; folderService: FolderServiceAbstraction;
@@ -122,12 +126,15 @@ export default class MainBackground {
searchService: SearchServiceAbstraction; searchService: SearchServiceAbstraction;
notificationsService: NotificationsServiceAbstraction; notificationsService: NotificationsServiceAbstraction;
stateService: StateServiceAbstraction; stateService: StateServiceAbstraction;
stateMigrationService: StateMigrationService;
systemService: SystemServiceAbstraction; systemService: SystemServiceAbstraction;
eventService: EventServiceAbstraction; eventService: EventServiceAbstraction;
policyService: PolicyServiceAbstraction; policyService: PolicyServiceAbstraction;
popupUtilsService: PopupUtilsService; popupUtilsService: PopupUtilsService;
sendService: SendServiceAbstraction; sendService: SendServiceAbstraction;
fileUploadService: FileUploadServiceAbstraction; fileUploadService: FileUploadServiceAbstraction;
organizationService: OrganizationServiceAbstraction;
providerService: ProviderServiceAbstraction;
keyConnectorService: KeyConnectorServiceAbstraction; keyConnectorService: KeyConnectorServiceAbstraction;
userVerificationService: UserVerificationServiceAbstraction; userVerificationService: UserVerificationServiceAbstraction;
@@ -155,9 +162,22 @@ export default class MainBackground {
// Services // Services
this.messagingService = new BrowserMessagingService(); this.messagingService = new BrowserMessagingService();
this.storageService = new BrowserStorageService(); this.storageService = new BrowserStorageService();
this.secureStorageService = new BrowserStorageService();
this.logService = new ConsoleLogService(false);
this.stateMigrationService = new StateMigrationService(
this.storageService,
this.secureStorageService
);
this.stateService = new StateService(
this.storageService,
this.secureStorageService,
this.logService,
this.stateMigrationService,
new AccountFactory(Account)
);
this.platformUtilsService = new BrowserPlatformUtilsService( this.platformUtilsService = new BrowserPlatformUtilsService(
this.messagingService, this.messagingService,
this.storageService, this.stateService,
(clipboardValue, clearMs) => { (clipboardValue, clearMs) => {
if (this.systemService != null) { if (this.systemService != null) {
this.systemService.clearClipboard(clipboardValue, clearMs); this.systemService.clearClipboard(clipboardValue, clearMs);
@@ -177,137 +197,139 @@ export default class MainBackground {
} }
} }
); );
this.secureStorageService = new BrowserStorageService();
this.i18nService = new I18nService(BrowserApi.getUILanguage(window)); this.i18nService = new I18nService(BrowserApi.getUILanguage(window));
this.cryptoFunctionService = new WebCryptoFunctionService(window, this.platformUtilsService); this.cryptoFunctionService = new WebCryptoFunctionService(window, this.platformUtilsService);
this.logService = new ConsoleLogService(false);
this.cryptoService = new BrowserCryptoService( this.cryptoService = new BrowserCryptoService(
this.storageService,
this.secureStorageService,
this.cryptoFunctionService, this.cryptoFunctionService,
this.platformUtilsService, this.platformUtilsService,
this.logService this.logService,
this.stateService
); );
this.tokenService = new TokenService(this.storageService); this.tokenService = new TokenService(this.stateService);
this.appIdService = new AppIdService(this.storageService); this.appIdService = new AppIdService(this.storageService);
this.environmentService = new EnvironmentService(this.storageService); this.environmentService = new EnvironmentService(this.stateService);
this.apiService = new ApiService( this.apiService = new ApiService(
this.tokenService, this.tokenService,
this.platformUtilsService, this.platformUtilsService,
this.environmentService, this.environmentService,
(expired: boolean) => this.logout(expired) (expired: boolean) => this.logout(expired)
); );
this.userService = new UserService(this.tokenService, this.storageService); this.settingsService = new SettingsService(this.stateService);
this.settingsService = new SettingsService(this.userService, this.storageService);
this.fileUploadService = new FileUploadService(this.logService, this.apiService); this.fileUploadService = new FileUploadService(this.logService, this.apiService);
this.cipherService = new CipherService( this.cipherService = new CipherService(
this.cryptoService, this.cryptoService,
this.userService,
this.settingsService, this.settingsService,
this.apiService, this.apiService,
this.fileUploadService, this.fileUploadService,
this.storageService,
this.i18nService, this.i18nService,
() => this.searchService, () => this.searchService,
this.logService this.logService,
this.stateService
); );
this.folderService = new FolderService( this.folderService = new FolderService(
this.cryptoService, this.cryptoService,
this.userService,
this.apiService, this.apiService,
this.storageService,
this.i18nService, this.i18nService,
this.cipherService this.cipherService,
this.stateService
); );
this.collectionService = new CollectionService( this.collectionService = new CollectionService(
this.cryptoService, this.cryptoService,
this.userService, this.i18nService,
this.storageService, this.stateService
this.i18nService
); );
this.searchService = new SearchService(this.cipherService, this.logService, this.i18nService); this.searchService = new SearchService(this.cipherService, this.logService, this.i18nService);
this.sendService = new SendService( this.sendService = new SendService(
this.cryptoService, this.cryptoService,
this.userService,
this.apiService, this.apiService,
this.fileUploadService, this.fileUploadService,
this.storageService,
this.i18nService, this.i18nService,
this.cryptoFunctionService this.cryptoFunctionService,
this.stateService
);
this.organizationService = new OrganizationService(this.stateService);
this.policyService = new PolicyService(
this.stateService,
this.organizationService,
this.apiService
); );
this.stateService = new StateService();
this.policyService = new PolicyService(this.userService, this.storageService, this.apiService);
this.keyConnectorService = new KeyConnectorService( this.keyConnectorService = new KeyConnectorService(
this.storageService, this.stateService,
this.userService,
this.cryptoService, this.cryptoService,
this.apiService, this.apiService,
this.tokenService, this.tokenService,
this.logService this.logService,
this.organizationService
); );
this.vaultTimeoutService = new VaultTimeoutService(
this.cipherService, const vaultTimeoutServiceCallbacks = {
this.folderService, locked: async () => {
this.collectionService,
this.cryptoService,
this.platformUtilsService,
this.storageService,
this.messagingService,
this.searchService,
this.userService,
this.tokenService,
this.policyService,
this.keyConnectorService,
async () => {
if (this.notificationsService != null) { if (this.notificationsService != null) {
this.notificationsService.updateConnection(false); this.notificationsService.updateConnection(false);
} }
await this.setIcon(); await this.setIcon();
await this.refreshBadgeAndMenu(true); await this.refreshBadgeAndMenu(true);
if (this.systemService != null) { if (this.systemService != null) {
this.systemService.startProcessReload();
await this.systemService.clearPendingClipboard(); await this.systemService.clearPendingClipboard();
await this.reloadProcess();
} }
}, },
async () => await this.logout(false) logout: async () => await this.logout(false),
};
this.vaultTimeoutService = new VaultTimeoutService(
this.cipherService,
this.folderService,
this.collectionService,
this.cryptoService,
this.platformUtilsService,
this.messagingService,
this.searchService,
this.tokenService,
this.policyService,
this.keyConnectorService,
this.stateService,
vaultTimeoutServiceCallbacks.locked,
vaultTimeoutServiceCallbacks.logout
); );
this.providerService = new ProviderService(this.stateService);
this.syncService = new SyncService( this.syncService = new SyncService(
this.userService,
this.apiService, this.apiService,
this.settingsService, this.settingsService,
this.folderService, this.folderService,
this.cipherService, this.cipherService,
this.cryptoService, this.cryptoService,
this.collectionService, this.collectionService,
this.storageService,
this.messagingService, this.messagingService,
this.policyService, this.policyService,
this.sendService, this.sendService,
this.logService, this.logService,
this.tokenService,
this.keyConnectorService, this.keyConnectorService,
this.stateService,
this.organizationService,
this.providerService,
async (expired: boolean) => await this.logout(expired) async (expired: boolean) => await this.logout(expired)
); );
this.eventService = new EventService( this.eventService = new EventService(
this.storageService,
this.apiService, this.apiService,
this.userService,
this.cipherService, this.cipherService,
this.logService this.stateService,
this.logService,
this.organizationService
); );
this.passwordGenerationService = new PasswordGenerationService( this.passwordGenerationService = new PasswordGenerationService(
this.cryptoService, this.cryptoService,
this.storageService, this.policyService,
this.policyService this.stateService
); );
this.totpService = new TotpService( this.totpService = new TotpService(
this.storageService,
this.cryptoFunctionService, this.cryptoFunctionService,
this.logService this.logService,
this.stateService
); );
this.autofillService = new AutofillService( this.autofillService = new AutofillService(
this.cipherService, this.cipherService,
this.userService, this.stateService,
this.totpService, this.totpService,
this.eventService, this.eventService,
this.logService this.logService
@@ -321,34 +343,37 @@ export default class MainBackground {
this.cryptoService this.cryptoService
); );
this.notificationsService = new NotificationsService( this.notificationsService = new NotificationsService(
this.userService,
this.syncService, this.syncService,
this.appIdService, this.appIdService,
this.apiService, this.apiService,
this.vaultTimeoutService, this.vaultTimeoutService,
this.environmentService, this.environmentService,
() => this.logout(true), () => this.logout(true),
this.logService this.logService,
this.stateService
); );
this.popupUtilsService = new PopupUtilsService(this.platformUtilsService); this.popupUtilsService = new PopupUtilsService(this.platformUtilsService);
this.systemService = new SystemService(
this.storageService, this.userVerificationService = new UserVerificationService(
this.vaultTimeoutService, this.cryptoService,
this.messagingService, this.i18nService,
this.platformUtilsService, this.apiService
() => { );
const systemUtilsServiceReloadCallback = () => {
const forceWindowReload = const forceWindowReload =
this.platformUtilsService.isSafari() || this.platformUtilsService.isSafari() ||
this.platformUtilsService.isFirefox() || this.platformUtilsService.isFirefox() ||
this.platformUtilsService.isOpera(); this.platformUtilsService.isOpera();
BrowserApi.reloadExtension(forceWindowReload ? window : null); BrowserApi.reloadExtension(forceWindowReload ? window : null);
return Promise.resolve(); return Promise.resolve();
} };
);
this.userVerificationService = new UserVerificationService( this.systemService = new SystemService(
this.cryptoService, this.messagingService,
this.i18nService, this.platformUtilsService,
this.apiService systemUtilsServiceReloadCallback,
this.stateService
); );
// Other fields // Other fields
@@ -364,25 +389,24 @@ export default class MainBackground {
this, this,
this.autofillService, this.autofillService,
this.platformUtilsService as BrowserPlatformUtilsService, this.platformUtilsService as BrowserPlatformUtilsService,
this.storageService,
this.i18nService, this.i18nService,
this.notificationsService, this.notificationsService,
this.systemService, this.systemService,
this.environmentService, this.environmentService,
this.messagingService, this.messagingService,
this.stateService,
this.logService this.logService
); );
this.nativeMessagingBackground = new NativeMessagingBackground( this.nativeMessagingBackground = new NativeMessagingBackground(
this.storageService,
this.cryptoService, this.cryptoService,
this.cryptoFunctionService, this.cryptoFunctionService,
this.vaultTimeoutService,
this.runtimeBackground, this.runtimeBackground,
this.i18nService, this.i18nService,
this.userService,
this.messagingService, this.messagingService,
this.appIdService, this.appIdService,
this.platformUtilsService this.platformUtilsService,
this.stateService,
this.logService
); );
this.commandsBackground = new CommandsBackground( this.commandsBackground = new CommandsBackground(
this, this,
@@ -394,11 +418,10 @@ export default class MainBackground {
this, this,
this.autofillService, this.autofillService,
this.cipherService, this.cipherService,
this.storageService,
this.vaultTimeoutService, this.vaultTimeoutService,
this.policyService, this.policyService,
this.folderService, this.folderService,
this.userService this.stateService
); );
this.tabsBackground = new TabsBackground(this, this.notificationBackground); this.tabsBackground = new TabsBackground(this, this.notificationBackground);
@@ -413,7 +436,7 @@ export default class MainBackground {
); );
this.idleBackground = new IdleBackground( this.idleBackground = new IdleBackground(
this.vaultTimeoutService, this.vaultTimeoutService,
this.storageService, this.stateService,
this.notificationsService this.notificationsService
); );
this.webRequestBackground = new WebRequestBackground( this.webRequestBackground = new WebRequestBackground(
@@ -424,32 +447,35 @@ export default class MainBackground {
this.windowsBackground = new WindowsBackground(this); this.windowsBackground = new WindowsBackground(this);
const that = this; const that = this;
this.authService = new AuthService( const backgroundMessagingService = new (class extends MessagingServiceAbstraction {
this.cryptoService,
this.apiService,
this.userService,
this.tokenService,
this.appIdService,
this.i18nService,
this.platformUtilsService,
new (class extends MessagingServiceAbstraction {
// AuthService should send the messages to the background not popup. // AuthService should send the messages to the background not popup.
send = (subscriber: string, arg: any = {}) => { send = (subscriber: string, arg: any = {}) => {
const message = Object.assign({}, { command: subscriber }, arg); const message = Object.assign({}, { command: subscriber }, arg);
that.runtimeBackground.processMessage(message, that, null); that.runtimeBackground.processMessage(message, that, null);
}; };
})(), })();
this.authService = new AuthService(
this.cryptoService,
this.apiService,
this.tokenService,
this.appIdService,
this.i18nService,
this.platformUtilsService,
backgroundMessagingService,
this.vaultTimeoutService, this.vaultTimeoutService,
this.logService, this.logService,
this.cryptoFunctionService, this.cryptoFunctionService,
this.keyConnectorService,
this.environmentService, this.environmentService,
this.keyConnectorService this.stateService
); );
} }
async bootstrap() { async bootstrap() {
this.containerService.attachToWindow(window); this.containerService.attachToWindow(window);
await this.stateService.init();
(this.authService as AuthService).init(); (this.authService as AuthService).init();
await (this.vaultTimeoutService as VaultTimeoutService).init(true); await (this.vaultTimeoutService as VaultTimeoutService).init(true);
await (this.i18nService as I18nService).init(); await (this.i18nService as I18nService).init();
@@ -480,7 +506,7 @@ export default class MainBackground {
return; return;
} }
const isAuthenticated = await this.userService.isAuthenticated(); const isAuthenticated = await this.stateService.getIsAuthenticated();
const locked = await this.vaultTimeoutService.isLocked(); const locked = await this.vaultTimeoutService.isLocked();
let suffix = ""; let suffix = "";
@@ -499,9 +525,7 @@ export default class MainBackground {
return; return;
} }
const menuDisabled = await this.storageService.get<boolean>( const menuDisabled = await this.stateService.getDisableContextMenuItem();
ConstantsService.disableContextMenuItemKey
);
if (!menuDisabled) { if (!menuDisabled) {
await this.buildContextMenu(); await this.buildContextMenu();
} else { } else {
@@ -520,35 +544,39 @@ export default class MainBackground {
} }
} }
async logout(expired: boolean) { async logout(expired: boolean, userId?: string) {
await this.eventService.uploadEvents(); if (!userId) {
const userId = await this.userService.getUserId(); userId = await this.stateService.getUserId();
}
await this.eventService.uploadEvents(userId);
await Promise.all([ await Promise.all([
this.eventService.clearEvents(), this.eventService.clearEvents(userId),
this.syncService.setLastSync(new Date(0)), this.syncService.setLastSync(new Date(0), userId),
this.tokenService.clearToken(), this.tokenService.clearToken(userId),
this.cryptoService.clearKeys(), this.cryptoService.clearKeys(userId),
this.userService.clear(),
this.settingsService.clear(userId), this.settingsService.clear(userId),
this.cipherService.clear(userId), this.cipherService.clear(userId),
this.folderService.clear(userId), this.folderService.clear(userId),
this.collectionService.clear(userId), this.collectionService.clear(userId),
this.policyService.clear(userId), this.policyService.clear(userId),
this.passwordGenerationService.clear(), this.passwordGenerationService.clear(userId),
this.vaultTimeoutService.clear(), this.vaultTimeoutService.clear(userId),
this.keyConnectorService.clear(), this.keyConnectorService.clear(),
]); ]);
if (userId == null || userId === (await this.stateService.getUserId())) {
this.searchService.clearIndex(); this.searchService.clearIndex();
this.messagingService.send("doneLoggingOut", { expired: expired }); this.messagingService.send("doneLoggingOut", { expired: expired, userId: userId });
}
await this.setIcon(); await this.setIcon();
await this.refreshBadgeAndMenu(); await this.refreshBadgeAndMenu();
await this.reseedStorage(); await this.reseedStorage();
this.notificationsService.updateConnection(false); this.notificationsService.updateConnection(false);
this.systemService.startProcessReload();
await this.systemService.clearPendingClipboard(); await this.systemService.clearPendingClipboard();
await this.reloadProcess();
} }
async collectPageDetailsForContentScript(tab: any, sender: string, frameId: number = null) { async collectPageDetailsForContentScript(tab: any, sender: string, frameId: number = null) {
@@ -591,9 +619,7 @@ export default class MainBackground {
return; return;
} }
const currentVaultTimeout = await this.storageService.get<number>( const currentVaultTimeout = await this.stateService.getVaultTimeout();
ConstantsService.vaultTimeoutKey
);
if (currentVaultTimeout == null) { if (currentVaultTimeout == null) {
return; return;
} }
@@ -658,7 +684,7 @@ export default class MainBackground {
title: this.i18nService.t("copyPassword"), title: this.i18nService.t("copyPassword"),
}); });
if (await this.userService.canAccessPremium()) { if (await this.stateService.getCanAccessPremium()) {
await this.contextMenusCreate({ await this.contextMenusCreate({
type: "normal", type: "normal",
id: "copy-totp", id: "copy-totp",
@@ -718,9 +744,7 @@ export default class MainBackground {
}); });
} }
const disableBadgeCounter = await this.storageService.get<boolean>( const disableBadgeCounter = await this.stateService.getDisableBadgeCounter();
ConstantsService.disableBadgeCounterKey
);
let theText = ""; let theText = "";
if (!disableBadgeCounter) { if (!disableBadgeCounter) {
@@ -749,7 +773,7 @@ export default class MainBackground {
private async loadMenuAndUpdateBadgeForNoAccessState(contextMenuEnabled: boolean) { private async loadMenuAndUpdateBadgeForNoAccessState(contextMenuEnabled: boolean) {
if (contextMenuEnabled) { if (contextMenuEnabled) {
const authed = await this.userService.isAuthenticated(); const authed = await this.stateService.getIsAuthenticated();
await this.loadNoLoginsContextMenuOptions( await this.loadNoLoginsContextMenuOptions(
this.i18nService.t(authed ? "unlockVaultMenu" : "loginToVaultMenu") this.i18nService.t(authed ? "unlockVaultMenu" : "loginToVaultMenu")
); );
@@ -830,7 +854,7 @@ export default class MainBackground {
}); });
} }
const canAccessPremium = await this.userService.canAccessPremium(); const canAccessPremium = await this.stateService.getCanAccessPremium();
if (canAccessPremium && (cipher == null || (cipher.login.totp && cipher.login.totp !== ""))) { if (canAccessPremium && (cipher == null || (cipher.login.totp && cipher.login.totp !== ""))) {
await this.contextMenusCreate({ await this.contextMenusCreate({
type: "normal", type: "normal",
@@ -957,4 +981,15 @@ export default class MainBackground {
}); });
} }
} }
private async reloadProcess(): Promise<void> {
const accounts = Object.keys(this.stateService.accounts.getValue());
for (const userId of accounts) {
if (!(await this.vaultTimeoutService.isLocked(userId))) {
return;
}
}
await this.systemService.startProcessReload();
}
} }

View File

@@ -2,14 +2,14 @@ import { AppIdService } from "jslib-common/abstractions/appId.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service"; import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StorageService } from "jslib-common/abstractions/storage.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
import { ConstantsService } from "jslib-common/services/constants.service";
import { Utils } from "jslib-common/misc/utils"; import { Utils } from "jslib-common/misc/utils";
import { EncString } from "jslib-common/models/domain/encString";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey"; import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { BrowserApi } from "../browser/browserApi"; import { BrowserApi } from "../browser/browserApi";
@@ -18,6 +18,40 @@ import RuntimeBackground from "./runtime.background";
const MessageValidTimeout = 10 * 1000; const MessageValidTimeout = 10 * 1000;
const EncryptionAlgorithm = "sha1"; const EncryptionAlgorithm = "sha1";
type Message = {
command: string;
// Filled in by this service
userId?: string;
timestamp?: number;
// Used for sharing secret
publicKey?: string;
};
type OuterMessage = {
message: Message | EncString;
appId: string;
};
type ReceiveMessage = {
timestamp: number;
command: string;
response?: any;
// Unlock key
keyB64?: string;
};
type ReceiveMessageOuter = {
command: string;
appId: string;
// Should only have one of these.
message?: EncString;
sharedSecret?: string;
};
export class NativeMessagingBackground { export class NativeMessagingBackground {
private connected = false; private connected = false;
private connecting: boolean; private connecting: boolean;
@@ -32,18 +66,17 @@ export class NativeMessagingBackground {
private validatingFingerprint: boolean; private validatingFingerprint: boolean;
constructor( constructor(
private storageService: StorageService,
private cryptoService: CryptoService, private cryptoService: CryptoService,
private cryptoFunctionService: CryptoFunctionService, private cryptoFunctionService: CryptoFunctionService,
private vaultTimeoutService: VaultTimeoutService,
private runtimeBackground: RuntimeBackground, private runtimeBackground: RuntimeBackground,
private i18nService: I18nService, private i18nService: I18nService,
private userService: UserService,
private messagingService: MessagingService, private messagingService: MessagingService,
private appIdService: AppIdService, private appIdService: AppIdService,
private platformUtilsService: PlatformUtilsService private platformUtilsService: PlatformUtilsService,
private stateService: StateService,
private logService: LogService
) { ) {
this.storageService.save(ConstantsService.biometricFingerprintValidated, false); this.stateService.setBiometricFingerprintValidated(false);
if (chrome?.permissions?.onAdded) { if (chrome?.permissions?.onAdded) {
// Reload extension to activate nativeMessaging // Reload extension to activate nativeMessaging
@@ -55,7 +88,7 @@ export class NativeMessagingBackground {
async connect() { async connect() {
this.appId = await this.appIdService.getAppId(); this.appId = await this.appIdService.getAppId();
this.storageService.save(ConstantsService.biometricFingerprintValidated, false); this.stateService.setBiometricFingerprintValidated(false);
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
this.port = BrowserApi.connectNative("com.8bit.bitwarden"); this.port = BrowserApi.connectNative("com.8bit.bitwarden");
@@ -74,7 +107,7 @@ export class NativeMessagingBackground {
connectedCallback(); connectedCallback();
} }
this.port.onMessage.addListener(async (message: any) => { this.port.onMessage.addListener(async (message: ReceiveMessageOuter) => {
switch (message.command) { switch (message.command) {
case "connected": case "connected":
connectedCallback(); connectedCallback();
@@ -107,7 +140,7 @@ export class NativeMessagingBackground {
if (this.validatingFingerprint) { if (this.validatingFingerprint) {
this.validatingFingerprint = false; this.validatingFingerprint = false;
this.storageService.save(ConstantsService.biometricFingerprintValidated, true); this.stateService.setBiometricFingerprintValidated(true);
} }
this.sharedSecret = new SymmetricCryptoKey(decrypted); this.sharedSecret = new SymmetricCryptoKey(decrypted);
this.secureSetupResolve(); this.secureSetupResolve();
@@ -181,25 +214,26 @@ export class NativeMessagingBackground {
}); });
} }
async send(message: any) { async send(message: Message) {
if (!this.connected) { if (!this.connected) {
await this.connect(); await this.connect();
} }
message.userId = await this.stateService.getUserId();
message.timestamp = Date.now();
if (this.platformUtilsService.isSafari()) { if (this.platformUtilsService.isSafari()) {
this.postMessage(message); this.postMessage(message as any);
} else { } else {
this.postMessage({ appId: this.appId, message: await this.encryptMessage(message) }); this.postMessage({ appId: this.appId, message: await this.encryptMessage(message) });
} }
} }
async encryptMessage(message: any) { async encryptMessage(message: Message) {
if (this.sharedSecret == null) { if (this.sharedSecret == null) {
await this.secureCommunication(); await this.secureCommunication();
} }
message.timestamp = Date.now();
return await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret); return await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret);
} }
@@ -209,13 +243,12 @@ export class NativeMessagingBackground {
}); });
} }
private postMessage(message: any) { private postMessage(message: OuterMessage) {
// Wrap in try-catch to when the port disconnected without triggering `onDisconnect`. // Wrap in try-catch to when the port disconnected without triggering `onDisconnect`.
try { try {
this.port.postMessage(message); this.port.postMessage(message);
} catch (e) { } catch (e) {
// tslint:disable-next-line this.logService.error("NativeMessaging port disconnected, disconnecting.");
console.error("NativeMessaging port disconnected, disconnecting.");
this.sharedSecret = null; this.sharedSecret = null;
this.privateKey = null; this.privateKey = null;
@@ -230,21 +263,22 @@ export class NativeMessagingBackground {
} }
} }
private async onMessage(rawMessage: any) { private async onMessage(rawMessage: ReceiveMessage | EncString) {
let message = rawMessage; let message = rawMessage as ReceiveMessage;
if (!this.platformUtilsService.isSafari()) { if (!this.platformUtilsService.isSafari()) {
message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecret)); message = JSON.parse(
await this.cryptoService.decryptToUtf8(rawMessage as EncString, this.sharedSecret)
);
} }
if (Math.abs(message.timestamp - Date.now()) > MessageValidTimeout) { if (Math.abs(message.timestamp - Date.now()) > MessageValidTimeout) {
// tslint:disable-next-line this.logService.error("NativeMessage is to old, ignoring.");
console.error("NativeMessage is to old, ignoring.");
return; return;
} }
switch (message.command) { switch (message.command) {
case "biometricUnlock": case "biometricUnlock":
await this.storageService.remove(ConstantsService.biometricAwaitingAcceptance); await this.stateService.setBiometricAwaitingAcceptance(null);
if (message.response === "not enabled") { if (message.response === "not enabled") {
this.messagingService.send("showDialog", { this.messagingService.send("showDialog", {
@@ -264,16 +298,16 @@ export class NativeMessagingBackground {
break; break;
} }
const enabled = await this.storageService.get(ConstantsService.biometricUnlockKey); const enabled = await this.stateService.getBiometricUnlock();
if (enabled === null || enabled === false) { if (enabled === null || enabled === false) {
if (message.response === "unlocked") { if (message.response === "unlocked") {
await this.storageService.save(ConstantsService.biometricUnlockKey, true); await this.stateService.setBiometricUnlock(true);
} }
break; break;
} }
// Ignore unlock if already unlockeded // Ignore unlock if already unlocked
if (!this.vaultTimeoutService.biometricLocked) { if (!(await this.stateService.getBiometricLocked())) {
break; break;
} }
@@ -284,24 +318,25 @@ export class NativeMessagingBackground {
// Verify key is correct by attempting to decrypt a secret // Verify key is correct by attempting to decrypt a secret
try { try {
await this.cryptoService.getFingerprint(await this.userService.getUserId()); await this.cryptoService.getFingerprint(await this.stateService.getUserId());
} catch (e) { } catch (e) {
// tslint:disable-next-line this.logService.error("Unable to verify key: " + e);
console.error("Unable to verify key:", e);
await this.cryptoService.clearKey(); await this.cryptoService.clearKey();
this.showWrongUserDialog(); this.showWrongUserDialog();
message = false; // Exit early
break; if (this.resolver) {
this.resolver(message);
}
return;
} }
this.vaultTimeoutService.biometricLocked = false; await this.stateService.setBiometricLocked(false);
this.runtimeBackground.processMessage({ command: "unlocked" }, null, null); this.runtimeBackground.processMessage({ command: "unlocked" }, null, null);
} }
break; break;
default: default:
// tslint:disable-next-line this.logService.error("NativeMessage, got unknown command: " + message.command);
console.error("NativeMessage, got unknown command: ", message.command);
} }
if (this.resolver) { if (this.resolver) {
@@ -317,13 +352,13 @@ export class NativeMessagingBackground {
this.sendUnencrypted({ this.sendUnencrypted({
command: "setupEncryption", command: "setupEncryption",
publicKey: Utils.fromBufferToB64(publicKey), publicKey: Utils.fromBufferToB64(publicKey),
userId: await this.userService.getUserId(), userId: await this.stateService.getUserId(),
}); });
return new Promise((resolve, reject) => (this.secureSetupResolve = resolve)); return new Promise((resolve, reject) => (this.secureSetupResolve = resolve));
} }
private async sendUnencrypted(message: any) { private async sendUnencrypted(message: Message) {
if (!this.connected) { if (!this.connected) {
await this.connect(); await this.connect();
} }
@@ -335,7 +370,7 @@ export class NativeMessagingBackground {
private async showFingerprintDialog() { private async showFingerprintDialog() {
const fingerprint = ( const fingerprint = (
await this.cryptoService.getFingerprint(await this.userService.getUserId(), this.publicKey) await this.cryptoService.getFingerprint(await this.stateService.getUserId(), this.publicKey)
).join(" "); ).join(" ");
this.messagingService.send("showDialog", { this.messagingService.send("showDialog", {

View File

@@ -7,12 +7,8 @@ import { LoginView } from "jslib-common/models/view/loginView";
import { CipherService } from "jslib-common/abstractions/cipher.service"; import { CipherService } from "jslib-common/abstractions/cipher.service";
import { FolderService } from "jslib-common/abstractions/folder.service"; import { FolderService } from "jslib-common/abstractions/folder.service";
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
import { ConstantsService } from "jslib-common/services/constants.service";
import { AutofillService } from "../services/abstractions/autofill.service"; import { AutofillService } from "../services/abstractions/autofill.service";
import { BrowserApi } from "../browser/browserApi"; import { BrowserApi } from "../browser/browserApi";
@@ -23,6 +19,7 @@ import { Utils } from "jslib-common/misc/utils";
import { PolicyType } from "jslib-common/enums/policyType"; import { PolicyType } from "jslib-common/enums/policyType";
import { StateService } from "../services/abstractions/state.service";
import AddChangePasswordQueueMessage from "./models/addChangePasswordQueueMessage"; import AddChangePasswordQueueMessage from "./models/addChangePasswordQueueMessage";
import AddLoginQueueMessage from "./models/addLoginQueueMessage"; import AddLoginQueueMessage from "./models/addLoginQueueMessage";
import AddLoginRuntimeMessage from "./models/addLoginRuntimeMessage"; import AddLoginRuntimeMessage from "./models/addLoginRuntimeMessage";
@@ -37,11 +34,10 @@ export default class NotificationBackground {
private main: MainBackground, private main: MainBackground,
private autofillService: AutofillService, private autofillService: AutofillService,
private cipherService: CipherService, private cipherService: CipherService,
private storageService: StorageService,
private vaultTimeoutService: VaultTimeoutService, private vaultTimeoutService: VaultTimeoutService,
private policyService: PolicyService, private policyService: PolicyService,
private folderService: FolderService, private folderService: FolderService,
private userService: UserService private stateService: StateService
) {} ) {}
async init() { async init() {
@@ -198,7 +194,7 @@ export default class NotificationBackground {
} }
private async addLogin(loginInfo: AddLoginRuntimeMessage, tab: chrome.tabs.Tab) { private async addLogin(loginInfo: AddLoginRuntimeMessage, tab: chrome.tabs.Tab) {
if (!(await this.userService.isAuthenticated())) { if (!(await this.stateService.getIsAuthenticated())) {
return; return;
} }
@@ -212,9 +208,7 @@ export default class NotificationBackground {
normalizedUsername = normalizedUsername.toLowerCase(); normalizedUsername = normalizedUsername.toLowerCase();
} }
const disabledAddLogin = await this.storageService.get<boolean>( const disabledAddLogin = await this.stateService.getDisableAddLoginNotification();
ConstantsService.disableAddLoginNotificationKey
);
if (await this.vaultTimeoutService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
if (disabledAddLogin) { if (disabledAddLogin) {
return; return;
@@ -246,9 +240,8 @@ export default class NotificationBackground {
usernameMatches.length === 1 && usernameMatches.length === 1 &&
usernameMatches[0].login.password !== loginInfo.password usernameMatches[0].login.password !== loginInfo.password
) { ) {
const disabledChangePassword = await this.storageService.get<boolean>( const disabledChangePassword =
ConstantsService.disableChangedPasswordNotificationKey await this.stateService.getDisableChangedPasswordNotification();
);
if (disabledChangePassword) { if (disabledChangePassword) {
return; return;
} }

View File

@@ -3,9 +3,8 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { NotificationsService } from "jslib-common/abstractions/notifications.service"; import { NotificationsService } from "jslib-common/abstractions/notifications.service";
import { StorageService } from "jslib-common/abstractions/storage.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { SystemService } from "jslib-common/abstractions/system.service"; import { SystemService } from "jslib-common/abstractions/system.service";
import { ConstantsService } from "jslib-common/services/constants.service";
import { AutofillService } from "../services/abstractions/autofill.service"; import { AutofillService } from "../services/abstractions/autofill.service";
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service"; import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
@@ -27,12 +26,12 @@ export default class RuntimeBackground {
private main: MainBackground, private main: MainBackground,
private autofillService: AutofillService, private autofillService: AutofillService,
private platformUtilsService: BrowserPlatformUtilsService, private platformUtilsService: BrowserPlatformUtilsService,
private storageService: StorageService,
private i18nService: I18nService, private i18nService: I18nService,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private systemService: SystemService, private systemService: SystemService,
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private messagingService: MessagingService, private messagingService: MessagingService,
private stateService: StateService,
private logService: LogService private logService: LogService
) { ) {
// onInstalled listener must be wired up before anything else, so we do it in the ctor // onInstalled listener must be wired up before anything else, so we do it in the ctor
@@ -87,7 +86,7 @@ export default class RuntimeBackground {
this.lockedVaultPendingNotifications.push(msg.data); this.lockedVaultPendingNotifications.push(msg.data);
break; break;
case "logout": case "logout":
await this.main.logout(msg.expired); await this.main.logout(msg.expired, msg.userId);
break; break;
case "syncCompleted": case "syncCompleted":
if (msg.successfully) { if (msg.successfully) {
@@ -220,29 +219,10 @@ export default class RuntimeBackground {
if (this.onInstalledReason != null) { if (this.onInstalledReason != null) {
if (this.onInstalledReason === "install") { if (this.onInstalledReason === "install") {
BrowserApi.createNewTab("https://bitwarden.com/browser-start/"); BrowserApi.createNewTab("https://bitwarden.com/browser-start/");
await this.setDefaultSettings();
} }
this.onInstalledReason = null; this.onInstalledReason = null;
} }
}, 100); }, 100);
} }
private async setDefaultSettings() {
// Default timeout option to "on restart".
const currentVaultTimeout = await this.storageService.get<number>(
ConstantsService.vaultTimeoutKey
);
if (currentVaultTimeout == null) {
await this.storageService.save(ConstantsService.vaultTimeoutKey, -1);
}
// Default action to "lock".
const currentVaultTimeoutAction = await this.storageService.get<string>(
ConstantsService.vaultTimeoutActionKey
);
if (currentVaultTimeoutAction == null) {
await this.storageService.save(ConstantsService.vaultTimeoutActionKey, "lock");
}
}
} }

32
src/models/account.ts Normal file
View File

@@ -0,0 +1,32 @@
import {
Account as BaseAccount,
AccountSettings as BaseAccountSettings,
} from "jslib-common/models/domain/account";
import { BrowserComponentState } from "./browserComponentState";
import { BrowserGroupingsComponentState } from "./browserGroupingsComponentState";
import { BrowserSendComponentState } from "./browserSendComponentState";
export class AccountSettings extends BaseAccountSettings {
vaultTimeout: number = -1; // On Restart
}
export class Account extends BaseAccount {
settings?: AccountSettings = new AccountSettings();
groupings?: BrowserGroupingsComponentState;
send?: BrowserSendComponentState;
ciphers?: BrowserComponentState;
sendType?: BrowserComponentState;
constructor(init: Partial<Account>) {
super(init);
Object.assign(this.settings, {
...new AccountSettings(),
...this.settings,
});
this.groupings = init?.groupings ?? new BrowserGroupingsComponentState();
this.send = init?.send ?? new BrowserSendComponentState();
this.ciphers = init?.ciphers ?? new BrowserComponentState();
this.sendType = init?.sendType ?? new BrowserComponentState();
}
}

View File

@@ -0,0 +1,4 @@
export class BrowserComponentState {
scrollY: number;
searchText: string;
}

View File

@@ -0,0 +1,17 @@
import { CipherType } from "jslib-common/enums/cipherType";
import { CipherView } from "jslib-common/models/view/cipherView";
import { CollectionView } from "jslib-common/models/view/collectionView";
import { FolderView } from "jslib-common/models/view/folderView";
import { BrowserComponentState } from "./browserComponentState";
export class BrowserGroupingsComponentState extends BrowserComponentState {
favoriteCiphers: CipherView[];
noFolderCiphers: CipherView[];
ciphers: CipherView[];
collectionCounts: Map<string, number>;
folderCounts: Map<string, number>;
typeCounts: Map<CipherType, number>;
folders: FolderView[];
collections: CollectionView[];
deletedCount: number;
}

View File

@@ -0,0 +1,8 @@
import { SendType } from "jslib-common/enums/sendType";
import { SendView } from "jslib-common/models/view/sendView";
import { BrowserComponentState } from "./browserComponentState";
export class BrowserSendComponentState extends BrowserComponentState {
sends: SendView[];
typeCounts: Map<SendType, number>;
}

View File

@@ -1,12 +1,10 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { ConstantsService } from "jslib-common/services/constants.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service"; import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StorageService } from "jslib-common/abstractions/storage.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { Utils } from "jslib-common/misc/utils"; import { Utils } from "jslib-common/misc/utils";
@@ -18,7 +16,7 @@ export class HomeComponent {
constructor( constructor(
protected platformUtilsService: PlatformUtilsService, protected platformUtilsService: PlatformUtilsService,
private passwordGenerationService: PasswordGenerationService, private passwordGenerationService: PasswordGenerationService,
private storageService: StorageService, private stateService: StateService,
private cryptoFunctionService: CryptoFunctionService, private cryptoFunctionService: CryptoFunctionService,
private environmentService: EnvironmentService private environmentService: EnvironmentService
) {} ) {}
@@ -41,8 +39,8 @@ export class HomeComponent {
const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, "sha256"); const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, "sha256");
const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash); const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
await this.storageService.save(ConstantsService.ssoCodeVerifierKey, codeVerifier); await this.stateService.setSsoCodeVerifier(codeVerifier);
await this.storageService.save(ConstantsService.ssoStateKey, state); await this.stateService.setSsoState(state);
let url = this.environmentService.getWebVaultUrl(); let url = this.environmentService.getWebVaultUrl();
if (url == null) { if (url == null) {

View File

@@ -2,8 +2,6 @@ import { Component, NgZone } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
import { ConstantsService } from "jslib-common/services/constants.service";
import { ApiService } from "jslib-common/abstractions/api.service"; import { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service";
@@ -13,8 +11,6 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
import { LockComponent as BaseLockComponent } from "jslib-angular/components/lock.component"; import { LockComponent as BaseLockComponent } from "jslib-angular/components/lock.component";
@@ -31,9 +27,7 @@ export class LockComponent extends BaseLockComponent {
i18nService: I18nService, i18nService: I18nService,
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
messagingService: MessagingService, messagingService: MessagingService,
userService: UserService,
cryptoService: CryptoService, cryptoService: CryptoService,
storageService: StorageService,
vaultTimeoutService: VaultTimeoutService, vaultTimeoutService: VaultTimeoutService,
environmentService: EnvironmentService, environmentService: EnvironmentService,
stateService: StateService, stateService: StateService,
@@ -47,9 +41,7 @@ export class LockComponent extends BaseLockComponent {
i18nService, i18nService,
platformUtilsService, platformUtilsService,
messagingService, messagingService,
userService,
cryptoService, cryptoService,
storageService,
vaultTimeoutService, vaultTimeoutService,
environmentService, environmentService,
stateService, stateService,
@@ -65,8 +57,7 @@ export class LockComponent extends BaseLockComponent {
async ngOnInit() { async ngOnInit() {
await super.ngOnInit(); await super.ngOnInit();
const disableAutoBiometricsPrompt = const disableAutoBiometricsPrompt =
(await this.storageService.get<boolean>(ConstantsService.disableAutoBiometricsPromptKey)) ?? (await this.stateService.getDisableAutoBiometricsPrompt()) ?? true;
true;
window.setTimeout(async () => { window.setTimeout(async () => {
document.getElementById(this.pinLock ? "pin" : "masterPassword").focus(); document.getElementById(this.pinLock ? "pin" : "masterPassword").focus();

View File

@@ -9,7 +9,6 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { LoginComponent as BaseLoginComponent } from "jslib-angular/components/login.component"; import { LoginComponent as BaseLoginComponent } from "jslib-angular/components/login.component";
@@ -19,6 +18,8 @@ import { LoginComponent as BaseLoginComponent } from "jslib-angular/components/l
templateUrl: "login.component.html", templateUrl: "login.component.html",
}) })
export class LoginComponent extends BaseLoginComponent { export class LoginComponent extends BaseLoginComponent {
protected alwaysRememberEmail: boolean = true;
constructor( constructor(
authService: AuthService, authService: AuthService,
router: Router, router: Router,
@@ -28,7 +29,6 @@ export class LoginComponent extends BaseLoginComponent {
protected environmentService: EnvironmentService, protected environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationService, protected passwordGenerationService: PasswordGenerationService,
protected cryptoFunctionService: CryptoFunctionService, protected cryptoFunctionService: CryptoFunctionService,
storageService: StorageService,
syncService: SyncService, syncService: SyncService,
logService: LogService, logService: LogService,
ngZone: NgZone ngZone: NgZone
@@ -42,7 +42,6 @@ export class LoginComponent extends BaseLoginComponent {
environmentService, environmentService,
passwordGenerationService, passwordGenerationService,
cryptoFunctionService, cryptoFunctionService,
storageService,
logService, logService,
ngZone ngZone
); );

View File

@@ -9,8 +9,8 @@ import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { SetPasswordComponent as BaseSetPasswordComponent } from "jslib-angular/components/set-password.component"; import { SetPasswordComponent as BaseSetPasswordComponent } from "jslib-angular/components/set-password.component";
@@ -24,7 +24,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
i18nService: I18nService, i18nService: I18nService,
cryptoService: CryptoService, cryptoService: CryptoService,
messagingService: MessagingService, messagingService: MessagingService,
userService: UserService, stateService: StateService,
passwordGenerationService: PasswordGenerationService, passwordGenerationService: PasswordGenerationService,
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
policyService: PolicyService, policyService: PolicyService,
@@ -36,14 +36,14 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
i18nService, i18nService,
cryptoService, cryptoService,
messagingService, messagingService,
userService,
passwordGenerationService, passwordGenerationService,
platformUtilsService, platformUtilsService,
policyService, policyService,
router, router,
apiService, apiService,
syncService, syncService,
route route,
stateService
); );
} }

View File

@@ -11,7 +11,6 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
@@ -28,7 +27,6 @@ export class SsoComponent extends BaseSsoComponent {
router: Router, router: Router,
i18nService: I18nService, i18nService: I18nService,
route: ActivatedRoute, route: ActivatedRoute,
storageService: StorageService,
stateService: StateService, stateService: StateService,
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
apiService: ApiService, apiService: ApiService,
@@ -44,7 +42,6 @@ export class SsoComponent extends BaseSsoComponent {
router, router,
i18nService, i18nService,
route, route,
storageService,
stateService, stateService,
platformUtilsService, platformUtilsService,
apiService, apiService,

View File

@@ -13,7 +13,6 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { TwoFactorComponent as BaseTwoFactorComponent } from "jslib-angular/components/two-factor.component"; import { TwoFactorComponent as BaseTwoFactorComponent } from "jslib-angular/components/two-factor.component";
@@ -42,7 +41,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
private popupUtilsService: PopupUtilsService, private popupUtilsService: PopupUtilsService,
stateService: StateService, stateService: StateService,
storageService: StorageService,
route: ActivatedRoute, route: ActivatedRoute,
private messagingService: MessagingService, private messagingService: MessagingService,
logService: LogService logService: LogService
@@ -56,7 +54,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
window, window,
environmentService, environmentService,
stateService, stateService,
storageService,
route, route,
logService logService
); );

View File

@@ -8,8 +8,8 @@ import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { UpdateTempPasswordComponent as BaseUpdateTempPasswordComponent } from "jslib-angular/components/update-temp-password.component"; import { UpdateTempPasswordComponent as BaseUpdateTempPasswordComponent } from "jslib-angular/components/update-temp-password.component";
@@ -60,7 +60,7 @@ export class UpdateTempPasswordComponent extends BaseUpdateTempPasswordComponent
passwordGenerationService: PasswordGenerationService, passwordGenerationService: PasswordGenerationService,
policyService: PolicyService, policyService: PolicyService,
cryptoService: CryptoService, cryptoService: CryptoService,
userService: UserService, stateService: StateService,
messagingService: MessagingService, messagingService: MessagingService,
apiService: ApiService, apiService: ApiService,
syncService: SyncService, syncService: SyncService,
@@ -72,9 +72,9 @@ export class UpdateTempPasswordComponent extends BaseUpdateTempPasswordComponent
passwordGenerationService, passwordGenerationService,
policyService, policyService,
cryptoService, cryptoService,
userService,
messagingService, messagingService,
apiService, apiService,
stateService,
syncService, syncService,
logService logService
); );

View File

@@ -11,10 +11,8 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service"; import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { ConstantsService } from "jslib-common/services/constants.service"; import { StateService } from "../services/abstractions/state.service";
import { routerTransition } from "./app-routing.animations"; import { routerTransition } from "./app-routing.animations";
@@ -31,7 +29,6 @@ export class AppComponent implements OnInit {
constructor( constructor(
private toastrService: ToastrService, private toastrService: ToastrService,
private storageService: StorageService,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
private authService: AuthService, private authService: AuthService,
private i18nService: I18nService, private i18nService: I18nService,
@@ -49,14 +46,19 @@ export class AppComponent implements OnInit {
if (BrowserApi.getBackgroundPage() == null) { if (BrowserApi.getBackgroundPage() == null) {
return; return;
} }
let activeUserId: string = null;
this.stateService.activeAccount.subscribe((userId) => {
activeUserId = userId;
});
this.ngZone.runOutsideAngular(() => { this.ngZone.runOutsideAngular(() => {
window.onmousemove = () => this.recordActivity(); if (activeUserId != null) {
window.onmousedown = () => this.recordActivity(); window.onmousedown = () => this.recordActivity(activeUserId);
window.ontouchstart = () => this.recordActivity(); window.ontouchstart = () => this.recordActivity(activeUserId);
window.onclick = () => this.recordActivity(); window.onclick = () => this.recordActivity(activeUserId);
window.onscroll = () => this.recordActivity(); window.onscroll = () => this.recordActivity(activeUserId);
window.onkeypress = () => this.recordActivity(); window.onkeypress = () => this.recordActivity(activeUserId);
}
}); });
(window as any).bitwardenPopupMainMessageListener = async ( (window as any).bitwardenPopupMainMessageListener = async (
@@ -66,7 +68,7 @@ export class AppComponent implements OnInit {
) => { ) => {
if (msg.command === "doneLoggingOut") { if (msg.command === "doneLoggingOut") {
this.ngZone.run(async () => { this.ngZone.run(async () => {
this.authService.logOut(() => { this.authService.logOut(async () => {
if (msg.expired) { if (msg.expired) {
this.showToast({ this.showToast({
type: "warning", type: "warning",
@@ -74,8 +76,12 @@ export class AppComponent implements OnInit {
text: this.i18nService.t("loginExpired"), text: this.i18nService.t("loginExpired"),
}); });
} }
await this.stateService.clean({ userId: msg.userId });
if (this.stateService.activeAccount.getValue() == null) {
this.router.navigate(["home"]); this.router.navigate(["home"]);
this.stateService.purge(); }
}); });
this.changeDetectorRef.detectChanges(); this.changeDetectorRef.detectChanges();
}); });
@@ -84,10 +90,11 @@ export class AppComponent implements OnInit {
this.router.navigate(["home"]); this.router.navigate(["home"]);
}); });
} else if (msg.command === "locked") { } else if (msg.command === "locked") {
this.stateService.purge(); if (msg.userId == null || msg.userId === (await this.stateService.getUserId())) {
this.ngZone.run(() => { this.ngZone.run(() => {
this.router.navigate(["lock"]); this.router.navigate(["lock"]);
}); });
}
} else if (msg.command === "showDialog") { } else if (msg.command === "showDialog") {
await this.showDialog(msg); await this.showDialog(msg);
} else if (msg.command === "showToast") { } else if (msg.command === "showToast") {
@@ -120,7 +127,7 @@ export class AppComponent implements OnInit {
BrowserApi.messageListener("app.component", (window as any).bitwardenPopupMainMessageListener); BrowserApi.messageListener("app.component", (window as any).bitwardenPopupMainMessageListener);
this.router.events.subscribe((event) => { this.router.events.subscribe(async (event) => {
if (event instanceof NavigationEnd) { if (event instanceof NavigationEnd) {
const url = event.urlAfterRedirects || event.url || ""; const url = event.urlAfterRedirects || event.url || "";
if ( if (
@@ -128,15 +135,13 @@ export class AppComponent implements OnInit {
(window as any).previousPopupUrl != null && (window as any).previousPopupUrl != null &&
(window as any).previousPopupUrl.startsWith("/tabs/") (window as any).previousPopupUrl.startsWith("/tabs/")
) { ) {
this.stateService.remove("GroupingsComponent"); await this.stateService.setBrowserGroupingComponentState(null);
this.stateService.remove("GroupingsComponentScope"); await this.stateService.setBrowserCipherComponentState(null);
this.stateService.remove("CiphersComponent"); await this.stateService.setBrowserSendComponentState(null);
this.stateService.remove("SendGroupingsComponent"); await this.stateService.setBrowserSendTypeComponentState(null);
this.stateService.remove("SendGroupingsComponentScope");
this.stateService.remove("SendTypeComponent");
} }
if (url.startsWith("/tabs/")) { if (url.startsWith("/tabs/")) {
this.stateService.remove("addEditCipherInfo"); await this.stateService.setAddEditCipherInfo(null);
} }
(window as any).previousPopupUrl = url; (window as any).previousPopupUrl = url;
@@ -167,14 +172,14 @@ export class AppComponent implements OnInit {
} }
} }
private async recordActivity() { private async recordActivity(userId: string) {
const now = new Date().getTime(); const now = new Date().getTime();
if (this.lastActivity != null && now - this.lastActivity < 250) { if (this.lastActivity != null && now - this.lastActivity < 250) {
return; return;
} }
this.lastActivity = now; this.lastActivity = now;
this.storageService.save(ConstantsService.lastActiveKey, now); this.stateService.setLastActive(now, { userId: userId });
} }
private showToast(msg: any) { private showToast(msg: any) {

View File

@@ -10,8 +10,8 @@ import { EventService } from "jslib-common/abstractions/event.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service"; import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { TotpService } from "jslib-common/abstractions/totp.service"; import { TotpService } from "jslib-common/abstractions/totp.service";
import { UserService } from "jslib-common/abstractions/user.service";
@Component({ @Component({
selector: "app-action-buttons", selector: "app-action-buttons",
@@ -31,12 +31,12 @@ export class ActionButtonsComponent {
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private eventService: EventService, private eventService: EventService,
private totpService: TotpService, private totpService: TotpService,
private userService: UserService, private stateService: StateService,
private passwordRepromptService: PasswordRepromptService private passwordRepromptService: PasswordRepromptService
) {} ) {}
async ngOnInit() { async ngOnInit() {
this.userHasPremiumAccess = await this.userService.canAccessPremium(); this.userHasPremiumAccess = await this.stateService.getCanAccessPremium();
} }
launchCipher() { launchCipher() {

View File

@@ -29,7 +29,7 @@ export class PasswordGeneratorComponent extends BasePasswordGeneratorComponent {
async ngOnInit() { async ngOnInit() {
await super.ngOnInit(); await super.ngOnInit();
const addEditCipherInfo = await this.stateService.get<any>("addEditCipherInfo"); const addEditCipherInfo = await this.stateService.getAddEditCipherInfo();
if (addEditCipherInfo != null) { if (addEditCipherInfo != null) {
this.cipherState = addEditCipherInfo.cipher; this.cipherState = addEditCipherInfo.cipher;
} }

View File

@@ -13,7 +13,8 @@ import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { SendService } from "jslib-common/abstractions/send.service"; import { SendService } from "jslib-common/abstractions/send.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { StateService } from "../../services/abstractions/state.service";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
@@ -36,7 +37,7 @@ export class SendAddEditComponent extends BaseAddEditComponent {
constructor( constructor(
i18nService: I18nService, i18nService: I18nService,
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
userService: UserService, stateService: StateService,
messagingService: MessagingService, messagingService: MessagingService,
policyService: PolicyService, policyService: PolicyService,
environmentService: EnvironmentService, environmentService: EnvironmentService,
@@ -54,10 +55,10 @@ export class SendAddEditComponent extends BaseAddEditComponent {
environmentService, environmentService,
datePipe, datePipe,
sendService, sendService,
userService,
messagingService, messagingService,
policyService, policyService,
logService logService,
stateService
); );
} }

View File

@@ -14,16 +14,16 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { SearchService } from "jslib-common/abstractions/search.service"; import { SearchService } from "jslib-common/abstractions/search.service";
import { SendService } from "jslib-common/abstractions/send.service"; import { SendService } from "jslib-common/abstractions/send.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { StateService } from "../../services/abstractions/state.service";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
import { SendType } from "jslib-common/enums/sendType"; import { SendType } from "jslib-common/enums/sendType";
import { BrowserSendComponentState } from "src/models/browserSendComponentState";
const ComponentId = "SendComponent"; const ComponentId = "SendComponent";
const ScopeStateId = ComponentId + "Scope";
@Component({ @Component({
selector: "app-send-groupings", selector: "app-send-groupings",
@@ -35,8 +35,7 @@ export class SendGroupingsComponent extends BaseSendComponent {
// Send Type Calculations // Send Type Calculations
typeCounts = new Map<SendType, number>(); typeCounts = new Map<SendType, number>();
// State Handling // State Handling
state: any; state: BrowserSendComponentState;
scopeState: any;
private loadedTimeout: number; private loadedTimeout: number;
constructor( constructor(
@@ -46,7 +45,6 @@ export class SendGroupingsComponent extends BaseSendComponent {
environmentService: EnvironmentService, environmentService: EnvironmentService,
ngZone: NgZone, ngZone: NgZone,
policyService: PolicyService, policyService: PolicyService,
userService: UserService,
searchService: SearchService, searchService: SearchService,
private popupUtils: PopupUtilsService, private popupUtils: PopupUtilsService,
private stateService: StateService, private stateService: StateService,
@@ -64,7 +62,6 @@ export class SendGroupingsComponent extends BaseSendComponent {
ngZone, ngZone,
searchService, searchService,
policyService, policyService,
userService,
logService logService
); );
super.onSuccessfulLoad = async () => { super.onSuccessfulLoad = async () => {
@@ -79,13 +76,12 @@ export class SendGroupingsComponent extends BaseSendComponent {
this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox() this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
); );
// Clear state of Send Type Component // Clear state of Send Type Component
this.stateService.remove("SendTypeComponent"); await this.stateService.setBrowserSendTypeComponentState(null);
// Let super class finish // Let super class finish
await super.ngOnInit(); await super.ngOnInit();
// Handle State Restore if necessary // Handle State Restore if necessary
const restoredScopeState = await this.restoreState(); const restoredScopeState = await this.restoreState();
this.state = (await this.stateService.get<any>(ComponentId)) || {}; if (this.state?.searchText != null) {
if (this.state.searchText != null) {
this.searchText = this.state.searchText; this.searchText = this.state.searchText;
} }
@@ -100,7 +96,7 @@ export class SendGroupingsComponent extends BaseSendComponent {
} }
if (!this.syncService.syncInProgress || restoredScopeState) { if (!this.syncService.syncInProgress || restoredScopeState) {
window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state.scrollY), 0); window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state?.scrollY), 0);
} }
// Load all sends if sync completed in background // Load all sends if sync completed in background
@@ -177,27 +173,23 @@ export class SendGroupingsComponent extends BaseSendComponent {
this.state = { this.state = {
scrollY: this.popupUtils.getContentScrollY(window), scrollY: this.popupUtils.getContentScrollY(window),
searchText: this.searchText, searchText: this.searchText,
};
await this.stateService.save(ComponentId, this.state);
this.scopeState = {
sends: this.sends, sends: this.sends,
typeCounts: this.typeCounts, typeCounts: this.typeCounts,
}; };
await this.stateService.save(ScopeStateId, this.scopeState); await this.stateService.setBrowserSendComponentState(this.state);
} }
private async restoreState(): Promise<boolean> { private async restoreState(): Promise<boolean> {
this.scopeState = await this.stateService.get<any>(ScopeStateId); this.state = await this.stateService.getBrowserSendComponentState();
if (this.scopeState == null) { if (this.state == null) {
return false; return false;
} }
if (this.scopeState.sends != null) { if (this.state.sends != null) {
this.sends = this.scopeState.sends; this.sends = this.state.sends;
} }
if (this.scopeState.typeCounts != null) { if (this.state.typeCounts != null) {
this.typeCounts = this.scopeState.typeCounts; this.typeCounts = this.state.typeCounts;
} }
return true; return true;

View File

@@ -18,13 +18,14 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { SearchService } from "jslib-common/abstractions/search.service"; import { SearchService } from "jslib-common/abstractions/search.service";
import { SendService } from "jslib-common/abstractions/send.service"; import { SendService } from "jslib-common/abstractions/send.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { StateService } from "../../services/abstractions/state.service";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
import { SendType } from "jslib-common/enums/sendType"; import { SendType } from "jslib-common/enums/sendType";
import { BrowserComponentState } from "../../models/browserComponentState";
const ComponentId = "SendTypeComponent"; const ComponentId = "SendTypeComponent";
@Component({ @Component({
@@ -34,7 +35,7 @@ const ComponentId = "SendTypeComponent";
export class SendTypeComponent extends BaseSendComponent { export class SendTypeComponent extends BaseSendComponent {
groupingTitle: string; groupingTitle: string;
// State Handling // State Handling
state: any; state: BrowserComponentState;
private refreshTimeout: number; private refreshTimeout: number;
private applySavedState = true; private applySavedState = true;
@@ -45,7 +46,6 @@ export class SendTypeComponent extends BaseSendComponent {
environmentService: EnvironmentService, environmentService: EnvironmentService,
ngZone: NgZone, ngZone: NgZone,
policyService: PolicyService, policyService: PolicyService,
userService: UserService,
searchService: SearchService, searchService: SearchService,
private popupUtils: PopupUtilsService, private popupUtils: PopupUtilsService,
private stateService: StateService, private stateService: StateService,
@@ -64,7 +64,6 @@ export class SendTypeComponent extends BaseSendComponent {
ngZone, ngZone,
searchService, searchService,
policyService, policyService,
userService,
logService logService
); );
super.onSuccessfulLoad = async () => { super.onSuccessfulLoad = async () => {
@@ -80,8 +79,8 @@ export class SendTypeComponent extends BaseSendComponent {
await super.ngOnInit(); await super.ngOnInit();
this.route.queryParams.pipe(first()).subscribe(async (params) => { this.route.queryParams.pipe(first()).subscribe(async (params) => {
if (this.applySavedState) { if (this.applySavedState) {
this.state = (await this.stateService.get<any>(ComponentId)) || {}; this.state = await this.stateService.getBrowserSendTypeComponentState();
if (this.state.searchText != null) { if (this.state?.searchText != null) {
this.searchText = this.state.searchText; this.searchText = this.state.searchText;
} }
} }
@@ -103,9 +102,9 @@ export class SendTypeComponent extends BaseSendComponent {
// Restore state and remove reference // Restore state and remove reference
if (this.applySavedState && this.state != null) { if (this.applySavedState && this.state != null) {
window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state.scrollY), 0); window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state?.scrollY), 0);
} }
this.stateService.remove(ComponentId); this.stateService.setBrowserSendTypeComponentState(null);
}); });
// Refresh Send list if sync completed in background // Refresh Send list if sync completed in background
@@ -167,6 +166,6 @@ export class SendTypeComponent extends BaseSendComponent {
scrollY: this.popupUtils.getContentScrollY(window), scrollY: this.popupUtils.getContentScrollY(window),
searchText: this.searchText, searchText: this.searchText,
}; };
await this.stateService.save(ComponentId, this.state); await this.stateService.setBrowserSendTypeComponentState(this.state);
} }
} }

View File

@@ -30,19 +30,20 @@ import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.serv
import { LogService as LogServiceAbstraction } from "jslib-common/abstractions/log.service"; import { LogService as LogServiceAbstraction } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { NotificationsService } from "jslib-common/abstractions/notifications.service"; import { NotificationsService } from "jslib-common/abstractions/notifications.service";
import { OrganizationService } from "jslib-common/abstractions/organization.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service"; import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { ProviderService } from "jslib-common/abstractions/provider.service";
import { SearchService as SearchServiceAbstraction } from "jslib-common/abstractions/search.service"; import { SearchService as SearchServiceAbstraction } from "jslib-common/abstractions/search.service";
import { SendService } from "jslib-common/abstractions/send.service"; import { SendService } from "jslib-common/abstractions/send.service";
import { SettingsService } from "jslib-common/abstractions/settings.service"; import { SettingsService } from "jslib-common/abstractions/settings.service";
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service"; import { StateService as BaseStateServiceAbstraction } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service"; import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { TokenService } from "jslib-common/abstractions/token.service"; import { TokenService } from "jslib-common/abstractions/token.service";
import { TotpService } from "jslib-common/abstractions/totp.service"; import { TotpService } from "jslib-common/abstractions/totp.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { UserVerificationService } from "jslib-common/abstractions/userVerification.service"; import { UserVerificationService } from "jslib-common/abstractions/userVerification.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
@@ -51,15 +52,15 @@ import BrowserMessagingService from "../../services/browserMessaging.service";
import { AuthService } from "jslib-common/services/auth.service"; import { AuthService } from "jslib-common/services/auth.service";
import { ConsoleLogService } from "jslib-common/services/consoleLog.service"; import { ConsoleLogService } from "jslib-common/services/consoleLog.service";
import { ConstantsService } from "jslib-common/services/constants.service";
import { SearchService } from "jslib-common/services/search.service"; import { SearchService } from "jslib-common/services/search.service";
import { StateService } from "jslib-common/services/state.service";
import { PopupSearchService } from "./popup-search.service"; import { PopupSearchService } from "./popup-search.service";
import { PopupUtilsService } from "./popup-utils.service"; import { PopupUtilsService } from "./popup-utils.service";
import { ThemeType } from "jslib-common/enums/themeType"; import { ThemeType } from "jslib-common/enums/themeType";
import { StateService as StateServiceAbstraction } from "../../services/abstractions/state.service";
function getBgService<T>(service: string) { function getBgService<T>(service: string) {
return (): T => { return (): T => {
const page = BrowserApi.getBackgroundPage(); const page = BrowserApi.getBackgroundPage();
@@ -72,12 +73,13 @@ const isPrivateMode = BrowserApi.getBackgroundPage() == null;
export function initFactory( export function initFactory(
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
i18nService: I18nService, i18nService: I18nService,
storageService: StorageService,
popupUtilsService: PopupUtilsService, popupUtilsService: PopupUtilsService,
stateService: StateServiceAbstraction, stateService: StateServiceAbstraction,
logService: LogServiceAbstraction logService: LogServiceAbstraction
): Function { ): Function {
return async () => { return async () => {
await stateService.init();
if (!popupUtilsService.inPopup(window)) { if (!popupUtilsService.inPopup(window)) {
window.document.body.classList.add("body-full"); window.document.body.classList.add("body-full");
} else if (window.screen.availHeight < 600) { } else if (window.screen.availHeight < 600) {
@@ -87,21 +89,11 @@ export function initFactory(
} }
if (!isPrivateMode) { if (!isPrivateMode) {
await stateService.save(
ConstantsService.disableFaviconKey,
await storageService.get<boolean>(ConstantsService.disableFaviconKey)
);
await stateService.save(
ConstantsService.disableBadgeCounterKey,
await storageService.get<boolean>(ConstantsService.disableBadgeCounterKey)
);
const htmlEl = window.document.documentElement; const htmlEl = window.document.documentElement;
const theme = await platformUtilsService.getEffectiveTheme(); const theme = await platformUtilsService.getEffectiveTheme();
htmlEl.classList.add("theme_" + theme); htmlEl.classList.add("theme_" + theme);
platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => { platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => {
const bwTheme = await storageService.get<ThemeType>(ConstantsService.themeKey); const bwTheme = await stateService.getTheme();
if (bwTheme == null || bwTheme === ThemeType.System) { if (bwTheme == null || bwTheme === ThemeType.System) {
htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark); htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark);
htmlEl.classList.add("theme_" + sysTheme); htmlEl.classList.add("theme_" + sysTheme);
@@ -143,7 +135,6 @@ export function initFactory(
deps: [ deps: [
PlatformUtilsService, PlatformUtilsService,
I18nService, I18nService,
StorageService,
PopupUtilsService, PopupUtilsService,
StateServiceAbstraction, StateServiceAbstraction,
LogServiceAbstraction, LogServiceAbstraction,
@@ -161,7 +152,6 @@ export function initFactory(
useFactory: getBgService<AuthService>("authService"), useFactory: getBgService<AuthService>("authService"),
deps: [], deps: [],
}, },
{ provide: StateServiceAbstraction, useClass: StateService },
{ {
provide: SearchServiceAbstraction, provide: SearchServiceAbstraction,
useFactory: ( useFactory: (
@@ -226,15 +216,14 @@ export function initFactory(
}, },
{ provide: ApiService, useFactory: getBgService<ApiService>("apiService"), deps: [] }, { provide: ApiService, useFactory: getBgService<ApiService>("apiService"), deps: [] },
{ provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] }, { provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] },
{ provide: UserService, useFactory: getBgService<UserService>("userService"), deps: [] },
{ {
provide: SettingsService, provide: SettingsService,
useFactory: getBgService<SettingsService>("settingsService"), useFactory: getBgService<SettingsService>("settingsService"),
deps: [], deps: [],
}, },
{ {
provide: StorageService, provide: StorageServiceAbstraction,
useFactory: getBgService<StorageService>("storageService"), useFactory: getBgService<StorageServiceAbstraction>("storageService"),
deps: [], deps: [],
}, },
{ provide: AppIdService, useFactory: getBgService<AppIdService>("appIdService"), deps: [] }, { provide: AppIdService, useFactory: getBgService<AppIdService>("appIdService"), deps: [] },
@@ -271,6 +260,31 @@ export function initFactory(
deps: [], deps: [],
}, },
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService }, { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
{
provide: OrganizationService,
useFactory: getBgService<OrganizationService>("organizationService"),
deps: [],
},
{
provide: ProviderService,
useFactory: getBgService<ProviderService>("providerService"),
deps: [],
},
{
provide: "SECURE_STORAGE",
useFactory: getBgService<StorageServiceAbstraction>("secureStorageService"),
deps: [],
},
{
provide: StateServiceAbstraction,
useFactory: getBgService<StateServiceAbstraction>("stateService"),
deps: [],
},
{
provide: BaseStateServiceAbstraction,
useExisting: StateServiceAbstraction,
deps: [],
},
], ],
}) })
export class ServicesModule {} export class ServicesModule {}

View File

@@ -2,12 +2,10 @@ import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { ConstantsService } from "jslib-common/services/constants.service";
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service"; import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StorageService } from "jslib-common/abstractions/storage.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { BrowserApi } from "../../browser/browserApi"; import { BrowserApi } from "../../browser/browserApi";
@@ -30,7 +28,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
loadCurrentUrisTimeout: number; loadCurrentUrisTimeout: number;
constructor( constructor(
private storageService: StorageService, private stateService: StateService,
private i18nService: I18nService, private i18nService: I18nService,
private router: Router, private router: Router,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
@@ -39,7 +37,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
) {} ) {}
async ngOnInit() { async ngOnInit() {
const savedDomains = await this.storageService.get<any>(ConstantsService.neverDomainsKey); const savedDomains = await this.stateService.getNeverDomains();
if (savedDomains) { if (savedDomains) {
for (const uri of Object.keys(savedDomains)) { for (const uri of Object.keys(savedDomains)) {
this.excludedDomains.push({ uri: uri, showCurrentUris: false }); this.excludedDomains.push({ uri: uri, showCurrentUris: false });
@@ -96,7 +94,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
savedDomains[validDomain] = null; savedDomains[validDomain] = null;
} }
} }
await this.storageService.save(ConstantsService.neverDomainsKey, savedDomains); await this.stateService.setNeverDomains(savedDomains);
this.router.navigate(["/tabs/settings"]); this.router.navigate(["/tabs/settings"]);
} }

View File

@@ -6,11 +6,8 @@ import { UriMatchType } from "jslib-common/enums/uriMatchType";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { StateService } from "jslib-common/abstractions/state.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { TotpService } from "jslib-common/abstractions/totp.service"; import { TotpService } from "jslib-common/abstractions/totp.service";
import { ConstantsService } from "jslib-common/services/constants.service";
@Component({ @Component({
selector: "app-options", selector: "app-options",
templateUrl: "options.component.html", templateUrl: "options.component.html",
@@ -40,7 +37,6 @@ export class OptionsComponent implements OnInit {
constructor( constructor(
private messagingService: MessagingService, private messagingService: MessagingService,
private storageService: StorageService,
private stateService: StateService, private stateService: StateService,
private totpService: TotpService, private totpService: TotpService,
i18nService: I18nService i18nService: I18nService
@@ -76,136 +72,89 @@ export class OptionsComponent implements OnInit {
} }
async ngOnInit() { async ngOnInit() {
this.enableAutoFillOnPageLoad = await this.storageService.get<boolean>( this.enableAutoFillOnPageLoad = await this.stateService.getEnableAutoFillOnPageLoad();
ConstantsService.enableAutoFillOnPageLoadKey
);
this.autoFillOnPageLoadDefault = this.autoFillOnPageLoadDefault =
(await this.storageService.get<boolean>(ConstantsService.autoFillOnPageLoadDefaultKey)) ?? (await this.stateService.getAutoFillOnPageLoadDefault()) ?? true;
true;
this.disableAddLoginNotification = await this.storageService.get<boolean>( this.disableAddLoginNotification = await this.stateService.getDisableAddLoginNotification();
ConstantsService.disableAddLoginNotificationKey
);
this.disableChangedPasswordNotification = await this.storageService.get<boolean>( this.disableChangedPasswordNotification =
ConstantsService.disableChangedPasswordNotificationKey await this.stateService.getDisableChangedPasswordNotification();
);
this.disableContextMenuItem = await this.storageService.get<boolean>( this.disableContextMenuItem = await this.stateService.getDisableContextMenuItem();
ConstantsService.disableContextMenuItemKey
);
this.dontShowCards = await this.storageService.get<boolean>( this.dontShowCards = await this.stateService.getDontShowCardsCurrentTab();
ConstantsService.dontShowCardsCurrentTab this.dontShowIdentities = await this.stateService.getDontShowIdentitiesCurrentTab();
);
this.dontShowIdentities = await this.storageService.get<boolean>(
ConstantsService.dontShowIdentitiesCurrentTab
);
this.disableAutoTotpCopy = !(await this.totpService.isAutoCopyEnabled()); this.disableAutoTotpCopy = !(await this.totpService.isAutoCopyEnabled());
this.disableFavicon = await this.storageService.get<boolean>( this.disableFavicon = await this.stateService.getDisableFavicon();
ConstantsService.disableFaviconKey
);
this.disableBadgeCounter = await this.storageService.get<boolean>( this.disableBadgeCounter = await this.stateService.getDisableBadgeCounter();
ConstantsService.disableBadgeCounterKey
);
this.theme = await this.storageService.get<string>(ConstantsService.themeKey); this.theme = await this.stateService.getTheme();
const defaultUriMatch = await this.storageService.get<UriMatchType>( const defaultUriMatch = await this.stateService.getDefaultUriMatch();
ConstantsService.defaultUriMatch
);
this.defaultUriMatch = defaultUriMatch == null ? UriMatchType.Domain : defaultUriMatch; this.defaultUriMatch = defaultUriMatch == null ? UriMatchType.Domain : defaultUriMatch;
this.clearClipboard = await this.storageService.get<number>(ConstantsService.clearClipboardKey); this.clearClipboard = await this.stateService.getClearClipboard();
} }
async updateAddLoginNotification() { async updateAddLoginNotification() {
await this.storageService.save( await this.stateService.setDisableAddLoginNotification(this.disableAddLoginNotification);
ConstantsService.disableAddLoginNotificationKey,
this.disableAddLoginNotification
);
} }
async updateChangedPasswordNotification() { async updateChangedPasswordNotification() {
await this.storageService.save( await this.stateService.setDisableChangedPasswordNotification(
ConstantsService.disableChangedPasswordNotificationKey,
this.disableChangedPasswordNotification this.disableChangedPasswordNotification
); );
} }
async updateDisableContextMenuItem() { async updateDisableContextMenuItem() {
await this.storageService.save( await this.stateService.setDisableContextMenuItem(this.disableContextMenuItem);
ConstantsService.disableContextMenuItemKey,
this.disableContextMenuItem
);
this.messagingService.send("bgUpdateContextMenu"); this.messagingService.send("bgUpdateContextMenu");
} }
async updateAutoTotpCopy() { async updateAutoTotpCopy() {
await this.storageService.save( await this.stateService.setDisableAutoTotpCopy(this.disableAutoTotpCopy);
ConstantsService.disableAutoTotpCopyKey,
this.disableAutoTotpCopy
);
} }
async updateAutoFillOnPageLoad() { async updateAutoFillOnPageLoad() {
await this.storageService.save( await this.stateService.setEnableAutoFillOnPageLoad(this.enableAutoFillOnPageLoad);
ConstantsService.enableAutoFillOnPageLoadKey,
this.enableAutoFillOnPageLoad
);
} }
async updateAutoFillOnPageLoadDefault() { async updateAutoFillOnPageLoadDefault() {
await this.storageService.save( await this.stateService.setAutoFillOnPageLoadDefault(this.autoFillOnPageLoadDefault);
ConstantsService.autoFillOnPageLoadDefaultKey,
this.autoFillOnPageLoadDefault
);
} }
async updateDisableFavicon() { async updateDisableFavicon() {
await this.storageService.save(ConstantsService.disableFaviconKey, this.disableFavicon); await this.stateService.setDisableFavicon(this.disableFavicon);
await this.stateService.save(ConstantsService.disableFaviconKey, this.disableFavicon);
} }
async updateDisableBadgeCounter() { async updateDisableBadgeCounter() {
await this.storageService.save( await this.stateService.setDisableBadgeCounter(this.disableBadgeCounter);
ConstantsService.disableBadgeCounterKey,
this.disableBadgeCounter
);
await this.stateService.save(ConstantsService.disableBadgeCounterKey, this.disableBadgeCounter);
this.messagingService.send("bgUpdateContextMenu"); this.messagingService.send("bgUpdateContextMenu");
} }
async updateShowCards() { async updateShowCards() {
await this.storageService.save(ConstantsService.dontShowCardsCurrentTab, this.dontShowCards); await this.stateService.setDontShowCardsCurrentTab(this.dontShowCards);
await this.stateService.save(ConstantsService.dontShowCardsCurrentTab, this.dontShowCards);
} }
async updateShowIdentities() { async updateShowIdentities() {
await this.storageService.save( await this.stateService.setDontShowIdentitiesCurrentTab(this.dontShowIdentities);
ConstantsService.dontShowIdentitiesCurrentTab,
this.dontShowIdentities
);
await this.stateService.save(
ConstantsService.dontShowIdentitiesCurrentTab,
this.dontShowIdentities
);
} }
async saveTheme() { async saveTheme() {
await this.storageService.save(ConstantsService.themeKey, this.theme); await this.stateService.setTheme(this.theme);
window.setTimeout(() => window.location.reload(), 200); window.setTimeout(() => window.location.reload(), 200);
} }
async saveDefaultUriMatch() { async saveDefaultUriMatch() {
await this.storageService.save(ConstantsService.defaultUriMatch, this.defaultUriMatch); await this.stateService.setDefaultUriMatch(this.defaultUriMatch);
} }
async saveClearClipboard() { async saveClearClipboard() {
await this.storageService.save(ConstantsService.clearClipboardKey, this.clearClipboard); await this.stateService.setClearClipboard(this.clearClipboard);
} }
} }

View File

@@ -5,7 +5,7 @@ import { ApiService } from "jslib-common/abstractions/api.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { UserService } from "jslib-common/abstractions/user.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { PremiumComponent as BasePremiumComponent } from "jslib-angular/components/premium.component"; import { PremiumComponent as BasePremiumComponent } from "jslib-angular/components/premium.component";
@@ -20,11 +20,11 @@ export class PremiumComponent extends BasePremiumComponent {
i18nService: I18nService, i18nService: I18nService,
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
apiService: ApiService, apiService: ApiService,
userService: UserService, stateService: StateService,
private currencyPipe: CurrencyPipe, logService: LogService,
logService: LogService private currencyPipe: CurrencyPipe
) { ) {
super(i18nService, platformUtilsService, apiService, userService, logService); super(i18nService, platformUtilsService, apiService, logService, stateService);
// Support old price string. Can be removed in future once all translations are properly updated. // Support old price string. Can be removed in future once all translations are properly updated.
const thePrice = this.currencyPipe.transform(this.price, "$"); const thePrice = this.currencyPipe.transform(this.price, "$");

View File

@@ -7,16 +7,13 @@ import { BrowserApi } from "../../browser/browserApi";
import { DeviceType } from "jslib-common/enums/deviceType"; import { DeviceType } from "jslib-common/enums/deviceType";
import { ConstantsService } from "jslib-common/services/constants.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service"; import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StorageService } from "jslib-common/abstractions/storage.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
@@ -61,12 +58,11 @@ export class SettingsComponent implements OnInit {
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService, private i18nService: I18nService,
private vaultTimeoutService: VaultTimeoutService, private vaultTimeoutService: VaultTimeoutService,
private storageService: StorageService,
public messagingService: MessagingService, public messagingService: MessagingService,
private router: Router, private router: Router,
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private cryptoService: CryptoService, private cryptoService: CryptoService,
private userService: UserService, private stateService: StateService,
private popupUtilsService: PopupUtilsService, private popupUtilsService: PopupUtilsService,
private modalService: ModalService, private modalService: ModalService,
private keyConnectorService: KeyConnectorService private keyConnectorService: KeyConnectorService
@@ -112,7 +108,7 @@ export class SettingsComponent implements OnInit {
this.saveVaultTimeout(value); this.saveVaultTimeout(value);
}); });
const action = await this.storageService.get<string>(ConstantsService.vaultTimeoutActionKey); const action = await this.stateService.getVaultTimeoutAction();
this.vaultTimeoutAction = action == null ? "lock" : action; this.vaultTimeoutAction = action == null ? "lock" : action;
const pinSet = await this.vaultTimeoutService.isPinLockSet(); const pinSet = await this.vaultTimeoutService.isPinLockSet();
@@ -121,8 +117,7 @@ export class SettingsComponent implements OnInit {
this.supportsBiometric = await this.platformUtilsService.supportsBiometric(); this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
this.biometric = await this.vaultTimeoutService.isBiometricLockSet(); this.biometric = await this.vaultTimeoutService.isBiometricLockSet();
this.disableAutoBiometricsPrompt = this.disableAutoBiometricsPrompt =
(await this.storageService.get<boolean>(ConstantsService.disableAutoBiometricsPromptKey)) ?? (await this.stateService.getDisableAutoBiometricsPrompt()) ?? true;
true;
this.showChangeMasterPass = !(await this.keyConnectorService.getUsesKeyConnector()); this.showChangeMasterPass = !(await this.keyConnectorService.getUsesKeyConnector());
} }
@@ -250,14 +245,14 @@ export class SettingsComponent implements OnInit {
allowOutsideClick: false, allowOutsideClick: false,
}); });
await this.storageService.save(ConstantsService.biometricAwaitingAcceptance, true); await this.stateService.setBiometricAwaitingAcceptance(true);
await this.cryptoService.toggleKey(); await this.cryptoService.toggleKey();
await Promise.race([ await Promise.race([
submitted.then((result) => { submitted.then(async (result) => {
if (result.dismiss === Swal.DismissReason.cancel) { if (result.dismiss === Swal.DismissReason.cancel) {
this.biometric = false; this.biometric = false;
this.storageService.remove(ConstantsService.biometricAwaitingAcceptance); await this.stateService.setBiometricAwaitingAcceptance(null);
} }
}), }),
this.platformUtilsService this.platformUtilsService
@@ -280,16 +275,13 @@ export class SettingsComponent implements OnInit {
}), }),
]); ]);
} else { } else {
await this.storageService.remove(ConstantsService.biometricUnlockKey); await this.stateService.setBiometricUnlock(null);
this.vaultTimeoutService.biometricLocked = false; await this.stateService.setBiometricLocked(false);
} }
} }
async updateAutoBiometricsPrompt() { async updateAutoBiometricsPrompt() {
await this.storageService.save( await this.stateService.setDisableAutoBiometricsPrompt(this.disableAutoBiometricsPrompt);
ConstantsService.disableAutoBiometricsPromptKey,
this.disableAutoBiometricsPrompt
);
} }
async lock() { async lock() {
@@ -385,7 +377,9 @@ export class SettingsComponent implements OnInit {
} }
async fingerprint() { async fingerprint() {
const fingerprint = await this.cryptoService.getFingerprint(await this.userService.getUserId()); const fingerprint = await this.cryptoService.getFingerprint(
await this.stateService.getUserId()
);
const p = document.createElement("p"); const p = document.createElement("p");
p.innerText = this.i18nService.t("yourAccountsFingerprint") + ":"; p.innerText = this.i18nService.t("yourAccountsFingerprint") + ":";
const p2 = document.createElement("p"); const p2 = document.createElement("p");

View File

@@ -14,14 +14,11 @@ import { FolderService } from "jslib-common/abstractions/folder.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { OrganizationService } from "jslib-common/abstractions/organization.service";
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service"; import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { ConstantsService } from "jslib-common/services/constants.service";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
@@ -48,7 +45,6 @@ export class AddEditComponent extends BaseAddEditComponent {
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
auditService: AuditService, auditService: AuditService,
stateService: StateService, stateService: StateService,
userService: UserService,
collectionService: CollectionService, collectionService: CollectionService,
messagingService: MessagingService, messagingService: MessagingService,
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -57,9 +53,9 @@ export class AddEditComponent extends BaseAddEditComponent {
eventService: EventService, eventService: EventService,
policyService: PolicyService, policyService: PolicyService,
private popupUtilsService: PopupUtilsService, private popupUtilsService: PopupUtilsService,
private storageService: StorageService, organizationService: OrganizationService,
logService: LogService, passwordRepromptService: PasswordRepromptService,
passwordRepromptService: PasswordRepromptService logService: LogService
) { ) {
super( super(
cipherService, cipherService,
@@ -68,13 +64,13 @@ export class AddEditComponent extends BaseAddEditComponent {
platformUtilsService, platformUtilsService,
auditService, auditService,
stateService, stateService,
userService,
collectionService, collectionService,
messagingService, messagingService,
eventService, eventService,
policyService, policyService,
logService,
passwordRepromptService, passwordRepromptService,
logService organizationService
); );
} }
@@ -149,7 +145,7 @@ export class AddEditComponent extends BaseAddEditComponent {
await super.load(); await super.load();
this.showAutoFillOnPageLoadOptions = this.showAutoFillOnPageLoadOptions =
this.cipher.type === CipherType.Login && this.cipher.type === CipherType.Login &&
(await this.storageService.get<boolean>(ConstantsService.enableAutoFillOnPageLoadKey)); (await this.stateService.getEnableAutoFillOnPageLoad());
} }
async submit(): Promise<boolean> { async submit(): Promise<boolean> {
@@ -194,7 +190,7 @@ export class AddEditComponent extends BaseAddEditComponent {
async generatePassword(): Promise<boolean> { async generatePassword(): Promise<boolean> {
const confirmed = await super.generatePassword(); const confirmed = await super.generatePassword();
if (confirmed) { if (confirmed) {
this.stateService.save("addEditCipherInfo", { this.stateService.setAddEditCipherInfo({
cipher: this.cipher, cipher: this.cipher,
collectionIds: collectionIds:
this.collections == null this.collections == null

View File

@@ -10,7 +10,7 @@ import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { UserService } from "jslib-common/abstractions/user.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { AttachmentsComponent as BaseAttachmentsComponent } from "jslib-angular/components/attachments.component"; import { AttachmentsComponent as BaseAttachmentsComponent } from "jslib-angular/components/attachments.component";
@@ -25,22 +25,22 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
cipherService: CipherService, cipherService: CipherService,
i18nService: I18nService, i18nService: I18nService,
cryptoService: CryptoService, cryptoService: CryptoService,
userService: UserService,
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
apiService: ApiService, apiService: ApiService,
private location: Location, private location: Location,
private route: ActivatedRoute, private route: ActivatedRoute,
stateService: StateService,
logService: LogService logService: LogService
) { ) {
super( super(
cipherService, cipherService,
i18nService, i18nService,
cryptoService, cryptoService,
userService,
platformUtilsService, platformUtilsService,
apiService, apiService,
window, window,
logService logService,
stateService
); );
} }

View File

@@ -13,18 +13,19 @@ import { FolderService } from "jslib-common/abstractions/folder.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { SearchService } from "jslib-common/abstractions/search.service"; import { SearchService } from "jslib-common/abstractions/search.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { CipherType } from "jslib-common/enums/cipherType"; import { CipherType } from "jslib-common/enums/cipherType";
import { TreeNode } from "jslib-common/models/domain/treeNode";
import { CipherView } from "jslib-common/models/view/cipherView"; import { CipherView } from "jslib-common/models/view/cipherView";
import { CollectionView } from "jslib-common/models/view/collectionView"; import { CollectionView } from "jslib-common/models/view/collectionView";
import { FolderView } from "jslib-common/models/view/folderView"; import { FolderView } from "jslib-common/models/view/folderView";
import { TreeNode } from "jslib-common/models/domain/treeNode";
import { CiphersComponent as BaseCiphersComponent } from "jslib-angular/components/ciphers.component"; import { CiphersComponent as BaseCiphersComponent } from "jslib-angular/components/ciphers.component";
import { BrowserComponentState } from "src/models/browserComponentState";
import { StateService } from "../../services/abstractions/state.service";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
const ComponentId = "CiphersComponent"; const ComponentId = "CiphersComponent";
@@ -35,7 +36,7 @@ const ComponentId = "CiphersComponent";
}) })
export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy { export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy {
groupingTitle: string; groupingTitle: string;
state: any; state: BrowserComponentState;
folderId: string = null; folderId: string = null;
collectionId: string = null; collectionId: string = null;
type: CipherType = null; type: CipherType = null;
@@ -74,8 +75,8 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
this.searchTypeSearch = !this.platformUtilsService.isSafari(); this.searchTypeSearch = !this.platformUtilsService.isSafari();
this.route.queryParams.pipe(first()).subscribe(async (params) => { this.route.queryParams.pipe(first()).subscribe(async (params) => {
if (this.applySavedState) { if (this.applySavedState) {
this.state = (await this.stateService.get<any>(ComponentId)) || {}; this.state = await this.stateService.getBrowserCipherComponentState();
if (this.state.searchText) { if (this.state?.searchText) {
this.searchText = this.state.searchText; this.searchText = this.state.searchText;
} }
} }
@@ -146,7 +147,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
0 0
); );
} }
this.stateService.remove(ComponentId); await this.stateService.setBrowserCipherComponentState(null);
}); });
this.broadcasterService.subscribe(ComponentId, (message: any) => { this.broadcasterService.subscribe(ComponentId, (message: any) => {
@@ -241,6 +242,6 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
scrollY: this.popupUtils.getContentScrollY(window, this.scrollingContainer), scrollY: this.popupUtils.getContentScrollY(window, this.scrollingContainer),
searchText: this.searchText, searchText: this.searchText,
}; };
await this.stateService.save(ComponentId, this.state); await this.stateService.setBrowserCipherComponentState(this.state);
} }
} }

View File

@@ -14,11 +14,9 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service"; import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { SearchService } from "jslib-common/abstractions/search.service"; import { SearchService } from "jslib-common/abstractions/search.service";
import { StorageService } from "jslib-common/abstractions/storage.service"; import { StateService } from "jslib-common/abstractions/state.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { ConstantsService } from "jslib-common/services/constants.service";
import { AutofillService } from "../../services/abstractions/autofill.service"; import { AutofillService } from "../../services/abstractions/autofill.service";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
@@ -60,7 +58,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private syncService: SyncService, private syncService: SyncService,
private searchService: SearchService, private searchService: SearchService,
private storageService: StorageService, private stateService: StateService,
private passwordRepromptService: PasswordRepromptService private passwordRepromptService: PasswordRepromptService
) {} ) {}
@@ -209,12 +207,8 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
}); });
const otherTypes: CipherType[] = []; const otherTypes: CipherType[] = [];
const dontShowCards = await this.storageService.get<boolean>( const dontShowCards = await this.stateService.getDontShowCardsCurrentTab();
ConstantsService.dontShowCardsCurrentTab const dontShowIdentities = await this.stateService.getDontShowIdentitiesCurrentTab();
);
const dontShowIdentities = await this.storageService.get<boolean>(
ConstantsService.dontShowIdentitiesCurrentTab
);
if (!dontShowCards) { if (!dontShowCards) {
otherTypes.push(CipherType.Card); otherTypes.push(CipherType.Card);
} }

View File

@@ -18,17 +18,17 @@ import { CollectionService } from "jslib-common/abstractions/collection.service"
import { FolderService } from "jslib-common/abstractions/folder.service"; import { FolderService } from "jslib-common/abstractions/folder.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { SearchService } from "jslib-common/abstractions/search.service"; import { SearchService } from "jslib-common/abstractions/search.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { GroupingsComponent as BaseGroupingsComponent } from "jslib-angular/components/groupings.component"; import { GroupingsComponent as BaseGroupingsComponent } from "jslib-angular/components/groupings.component";
import { StateService } from "../../services/abstractions/state.service";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
import { BrowserGroupingsComponentState } from "src/models/browserGroupingsComponentState";
const ComponentId = "GroupingsComponent"; const ComponentId = "GroupingsComponent";
const ScopeStateId = ComponentId + "Scope";
@Component({ @Component({
selector: "app-vault-groupings", selector: "app-vault-groupings",
@@ -53,8 +53,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
collectionCounts = new Map<string, number>(); collectionCounts = new Map<string, number>();
typeCounts = new Map<CipherType, number>(); typeCounts = new Map<CipherType, number>();
searchText: string; searchText: string;
state: any; state: BrowserGroupingsComponentState;
scopeState: any;
showLeftHeader = true; showLeftHeader = true;
searchPending = false; searchPending = false;
searchTypeSearch = false; searchTypeSearch = false;
@@ -72,22 +71,20 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
constructor( constructor(
collectionService: CollectionService, collectionService: CollectionService,
folderService: FolderService, folderService: FolderService,
storageService: StorageService,
userService: UserService,
private cipherService: CipherService, private cipherService: CipherService,
private router: Router, private router: Router,
private ngZone: NgZone, private ngZone: NgZone,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private route: ActivatedRoute, private route: ActivatedRoute,
private stateService: StateService,
private popupUtils: PopupUtilsService, private popupUtils: PopupUtilsService,
private syncService: SyncService, private syncService: SyncService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private searchService: SearchService, private searchService: SearchService,
private location: Location private location: Location,
private browserStateService: StateService
) { ) {
super(collectionService, folderService, storageService, userService); super(collectionService, folderService, browserStateService);
this.noFolderListSize = 100; this.noFolderListSize = 100;
} }
@@ -96,7 +93,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
this.showLeftHeader = !( this.showLeftHeader = !(
this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox() this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
); );
this.stateService.remove("CiphersComponent"); await this.browserStateService.setBrowserCipherComponentState(null);
this.broadcasterService.subscribe(ComponentId, (message: any) => { this.broadcasterService.subscribe(ComponentId, (message: any) => {
this.ngZone.run(async () => { this.ngZone.run(async () => {
@@ -116,8 +113,8 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
const restoredScopeState = await this.restoreState(); const restoredScopeState = await this.restoreState();
this.route.queryParams.pipe(first()).subscribe(async (params) => { this.route.queryParams.pipe(first()).subscribe(async (params) => {
this.state = (await this.stateService.get<any>(ComponentId)) || {}; this.state = await this.browserStateService.getBrowserGroupingComponentState();
if (this.state.searchText) { if (this.state?.searchText) {
this.searchText = this.state.searchText; this.searchText = this.state.searchText;
} else if (params.searchText) { } else if (params.searchText) {
this.searchText = params.searchText; this.searchText = params.searchText;
@@ -135,7 +132,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
} }
if (!this.syncService.syncInProgress || restoredScopeState) { if (!this.syncService.syncInProgress || restoredScopeState) {
window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state.scrollY), 0); window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state?.scrollY), 0);
} }
}); });
} }
@@ -320,10 +317,6 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
this.state = { this.state = {
scrollY: this.popupUtils.getContentScrollY(window), scrollY: this.popupUtils.getContentScrollY(window),
searchText: this.searchText, searchText: this.searchText,
};
await this.stateService.save(ComponentId, this.state);
this.scopeState = {
favoriteCiphers: this.favoriteCiphers, favoriteCiphers: this.favoriteCiphers,
noFolderCiphers: this.noFolderCiphers, noFolderCiphers: this.noFolderCiphers,
ciphers: this.ciphers, ciphers: this.ciphers,
@@ -334,41 +327,41 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
collections: this.collections, collections: this.collections,
deletedCount: this.deletedCount, deletedCount: this.deletedCount,
}; };
await this.stateService.save(ScopeStateId, this.scopeState); await this.browserStateService.setBrowserGroupingComponentState(this.state);
} }
private async restoreState(): Promise<boolean> { private async restoreState(): Promise<boolean> {
this.scopeState = await this.stateService.get<any>(ScopeStateId); this.state = await this.browserStateService.getBrowserGroupingComponentState();
if (this.scopeState == null) { if (this.state == null) {
return false; return false;
} }
if (this.scopeState.favoriteCiphers != null) { if (this.state.favoriteCiphers != null) {
this.favoriteCiphers = this.scopeState.favoriteCiphers; this.favoriteCiphers = this.state.favoriteCiphers;
} }
if (this.scopeState.noFolderCiphers != null) { if (this.state.noFolderCiphers != null) {
this.noFolderCiphers = this.scopeState.noFolderCiphers; this.noFolderCiphers = this.state.noFolderCiphers;
} }
if (this.scopeState.ciphers != null) { if (this.state.ciphers != null) {
this.ciphers = this.scopeState.ciphers; this.ciphers = this.state.ciphers;
} }
if (this.scopeState.collectionCounts != null) { if (this.state.collectionCounts != null) {
this.collectionCounts = this.scopeState.collectionCounts; this.collectionCounts = this.state.collectionCounts;
} }
if (this.scopeState.folderCounts != null) { if (this.state.folderCounts != null) {
this.folderCounts = this.scopeState.folderCounts; this.folderCounts = this.state.folderCounts;
} }
if (this.scopeState.typeCounts != null) { if (this.state.typeCounts != null) {
this.typeCounts = this.scopeState.typeCounts; this.typeCounts = this.state.typeCounts;
} }
if (this.scopeState.folders != null) { if (this.state.folders != null) {
this.folders = this.scopeState.folders; this.folders = this.state.folders;
} }
if (this.scopeState.collections != null) { if (this.state.collections != null) {
this.collections = this.scopeState.collections; this.collections = this.state.collections;
} }
if (this.scopeState.deletedCiphers != null) { if (this.state.deletedCount != null) {
this.deletedCount = this.scopeState.deletedCount; this.deletedCount = this.state.deletedCount;
} }
return true; return true;

View File

@@ -1,4 +1,3 @@
import { Location } from "@angular/common";
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router"; import { ActivatedRoute, Router } from "@angular/router";
@@ -8,8 +7,8 @@ import { CipherService } from "jslib-common/abstractions/cipher.service";
import { CollectionService } from "jslib-common/abstractions/collection.service"; import { CollectionService } from "jslib-common/abstractions/collection.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { OrganizationService } from "jslib-common/abstractions/organization.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { ShareComponent as BaseShareComponent } from "jslib-angular/components/share.component"; import { ShareComponent as BaseShareComponent } from "jslib-angular/components/share.component";
@@ -22,19 +21,19 @@ export class ShareComponent extends BaseShareComponent {
collectionService: CollectionService, collectionService: CollectionService,
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
i18nService: I18nService, i18nService: I18nService,
userService: UserService, logService: LogService,
cipherService: CipherService, cipherService: CipherService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
logService: LogService organizationService: OrganizationService
) { ) {
super( super(
collectionService, collectionService,
platformUtilsService, platformUtilsService,
i18nService, i18nService,
userService,
cipherService, cipherService,
logService logService,
organizationService
); );
} }

View File

@@ -15,9 +15,9 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service"; import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { TokenService } from "jslib-common/abstractions/token.service"; import { TokenService } from "jslib-common/abstractions/token.service";
import { TotpService } from "jslib-common/abstractions/totp.service"; import { TotpService } from "jslib-common/abstractions/totp.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { Cipher } from "jslib-common/models/domain/cipher"; import { Cipher } from "jslib-common/models/domain/cipher";
import { LoginUriView } from "jslib-common/models/view/loginUriView"; import { LoginUriView } from "jslib-common/models/view/loginUriView";
@@ -57,7 +57,7 @@ export class ViewComponent extends BaseViewComponent {
broadcasterService: BroadcasterService, broadcasterService: BroadcasterService,
ngZone: NgZone, ngZone: NgZone,
changeDetectorRef: ChangeDetectorRef, changeDetectorRef: ChangeDetectorRef,
userService: UserService, stateService: StateService,
eventService: EventService, eventService: EventService,
private autofillService: AutofillService, private autofillService: AutofillService,
private messagingService: MessagingService, private messagingService: MessagingService,
@@ -78,11 +78,11 @@ export class ViewComponent extends BaseViewComponent {
broadcasterService, broadcasterService,
ngZone, ngZone,
changeDetectorRef, changeDetectorRef,
userService,
eventService, eventService,
apiService, apiService,
passwordRepromptService, passwordRepromptService,
logService logService,
stateService
); );
} }

View File

@@ -115,13 +115,17 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
} }
laContext.evaluateAccessControl(accessControl, operation: .useKeySign, localizedReason: "Bitwarden Safari Extension") { (success, error) in laContext.evaluateAccessControl(accessControl, operation: .useKeySign, localizedReason: "Bitwarden Safari Extension") { (success, error) in
if success { if success {
let passwordName = "key" guard let userId = message?["userId"] as? String else {
return
}
let passwordName = userId + "_masterkey_biometric"
var passwordLength: UInt32 = 0 var passwordLength: UInt32 = 0
var passwordPtr: UnsafeMutableRawPointer? = nil var passwordPtr: UnsafeMutableRawPointer? = nil
var status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(passwordName.utf8.count), passwordName, &passwordLength, &passwordPtr, nil) var status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(passwordName.utf8.count), passwordName, &passwordLength, &passwordPtr, nil)
if status != errSecSuccess { if status != errSecSuccess {
status = SecKeychainFindGenericPassword(nil, UInt32(ServiceName.utf8.count), ServiceName, UInt32(passwordName.utf8.count), passwordName, &passwordLength, &passwordPtr, nil) let fallbackName = "key"
status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(fallbackName.utf8.count), fallbackName, &passwordLength, &passwordPtr, nil)
} }
if status == errSecSuccess { if status == errSecSuccess {

View File

@@ -0,0 +1,33 @@
import { StateService as BaseStateServiceAbstraction } from "jslib-common/abstractions/state.service";
import { StorageOptions } from "jslib-common/models/domain/storageOptions";
import { Account } from "src/models/account";
import { BrowserComponentState } from "src/models/browserComponentState";
import { BrowserGroupingsComponentState } from "src/models/browserGroupingsComponentState";
import { BrowserSendComponentState } from "src/models/browserSendComponentState";
export abstract class StateService extends BaseStateServiceAbstraction<Account> {
getBrowserGroupingComponentState: (
options?: StorageOptions
) => Promise<BrowserGroupingsComponentState>;
setBrowserGroupingComponentState: (
value: BrowserGroupingsComponentState,
options?: StorageOptions
) => Promise<void>;
getBrowserCipherComponentState: (options?: StorageOptions) => Promise<BrowserComponentState>;
setBrowserCipherComponentState: (
value: BrowserComponentState,
options?: StorageOptions
) => Promise<void>;
getBrowserSendComponentState: (options?: StorageOptions) => Promise<BrowserSendComponentState>;
setBrowserSendComponentState: (
value: BrowserSendComponentState,
options?: StorageOptions
) => Promise<void>;
getBrowserSendTypeComponentState: (options?: StorageOptions) => Promise<BrowserComponentState>;
setBrowserSendTypeComponentState: (
value: BrowserComponentState,
options?: StorageOptions
) => Promise<void>;
}

View File

@@ -2,7 +2,6 @@ import { CipherService } from "jslib-common/abstractions/cipher.service";
import { EventService } from "jslib-common/abstractions/event.service"; import { EventService } from "jslib-common/abstractions/event.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { TotpService } from "jslib-common/abstractions/totp.service"; import { TotpService } from "jslib-common/abstractions/totp.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { AutofillService as AutofillServiceInterface } from "./abstractions/autofill.service"; import { AutofillService as AutofillServiceInterface } from "./abstractions/autofill.service";
@@ -18,6 +17,8 @@ import AutofillField from "../models/autofillField";
import AutofillPageDetails from "../models/autofillPageDetails"; import AutofillPageDetails from "../models/autofillPageDetails";
import AutofillScript from "../models/autofillScript"; import AutofillScript from "../models/autofillScript";
import { StateService } from "../services/abstractions/state.service";
import { BrowserApi } from "../browser/browserApi"; import { BrowserApi } from "../browser/browserApi";
import { import {
@@ -29,7 +30,7 @@ import {
export default class AutofillService implements AutofillServiceInterface { export default class AutofillService implements AutofillServiceInterface {
constructor( constructor(
private cipherService: CipherService, private cipherService: CipherService,
private userService: UserService, private stateService: StateService,
private totpService: TotpService, private totpService: TotpService,
private eventService: EventService, private eventService: EventService,
private logService: LogService private logService: LogService
@@ -74,7 +75,7 @@ export default class AutofillService implements AutofillServiceInterface {
throw new Error("Nothing to auto-fill."); throw new Error("Nothing to auto-fill.");
} }
const canAccessPremium = await this.userService.canAccessPremium(); const canAccessPremium = await this.stateService.getCanAccessPremium();
let didAutofill = false; let didAutofill = false;
options.pageDetails.forEach((pd: any) => { options.pageDetails.forEach((pd: any) => {
// make sure we're still on correct tab // make sure we're still on correct tab

View File

@@ -1,4 +1,4 @@
import { KeySuffixOptions } from "jslib-common/abstractions/storage.service"; import { KeySuffixOptions } from "jslib-common/enums/keySuffixOptions";
import { CryptoService } from "jslib-common/services/crypto.service"; import { CryptoService } from "jslib-common/services/crypto.service";
export class BrowserCryptoService extends CryptoService { export class BrowserCryptoService extends CryptoService {

View File

@@ -6,9 +6,8 @@ import { ThemeType } from "jslib-common/enums/themeType";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { ConstantsService } from "jslib-common/services/constants.service"; import { StateService } from "../services/abstractions/state.service";
const DialogPromiseExpiration = 600000; // 10 minutes const DialogPromiseExpiration = 600000; // 10 minutes
@@ -25,7 +24,7 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
constructor( constructor(
private messagingService: MessagingService, private messagingService: MessagingService,
private storageService: StorageService, private stateService: StateService,
private clipboardWriteCallback: (clipboardValue: string, clearMs: number) => void, private clipboardWriteCallback: (clipboardValue: string, clearMs: number) => void,
private biometricCallback: () => Promise<boolean> private biometricCallback: () => Promise<boolean>
) {} ) {}
@@ -367,7 +366,7 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
} }
async getEffectiveTheme() { async getEffectiveTheme() {
const theme = await this.storageService.get<ThemeType>(ConstantsService.themeKey); const theme = (await this.stateService.getTheme()) as ThemeType;
if (theme == null || theme === ThemeType.System) { if (theme == null || theme === ThemeType.System) {
return this.getDefaultSystemTheme(); return this.getDefaultSystemTheme();
} else { } else {

View File

@@ -0,0 +1,81 @@
import { StorageOptions } from "jslib-common/models/domain/storageOptions";
import { StateService as BaseStateService } from "jslib-common/services/state.service";
import { Account } from "../models/account";
import { BrowserComponentState } from "../models/browserComponentState";
import { BrowserGroupingsComponentState } from "../models/browserGroupingsComponentState";
import { BrowserSendComponentState } from "../models/browserSendComponentState";
import { StateService as StateServiceAbstraction } from "./abstractions/state.service";
export class StateService extends BaseStateService<Account> implements StateServiceAbstraction {
async addAccount(account: Account) {
// Apply browser overrides to default account values
account = new Account(account);
await super.addAccount(account);
}
async getBrowserGroupingComponentState(
options?: StorageOptions
): Promise<BrowserGroupingsComponentState> {
return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions)))
?.groupings;
}
async setBrowserGroupingComponentState(
value: BrowserGroupingsComponentState,
options?: StorageOptions
): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, this.defaultInMemoryOptions)
);
account.groupings = value;
await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions));
}
async getBrowserCipherComponentState(options?: StorageOptions): Promise<BrowserComponentState> {
return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions)))
?.ciphers;
}
async setBrowserCipherComponentState(
value: BrowserComponentState,
options?: StorageOptions
): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, this.defaultInMemoryOptions)
);
account.ciphers = value;
await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions));
}
async getBrowserSendComponentState(options?: StorageOptions): Promise<BrowserSendComponentState> {
return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions)))
?.send;
}
async setBrowserSendComponentState(
value: BrowserSendComponentState,
options?: StorageOptions
): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, this.defaultInMemoryOptions)
);
account.send = value;
await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions));
}
async getBrowserSendTypeComponentState(options?: StorageOptions): Promise<BrowserComponentState> {
return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions)))
?.sendType;
}
async setBrowserSendTypeComponentState(
value: BrowserComponentState,
options?: StorageOptions
): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, this.defaultInMemoryOptions)
);
account.sendType = value;
await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions));
}
}