[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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 663 additions and 527 deletions

2
jslib

@ -1 +1 @@
Subproject commit 8fc3cf50d2967212ffbbf0d57cac71d0774aa2a8
Subproject commit 4722a287ec7212b8e67d02ec7ea1a9be0990ee6e

View File

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

View File

@ -1,6 +1,7 @@
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
import { CipherType } from "jslib-common/enums/cipherType";
import { AccountFactory } from "jslib-common/models/domain/account";
import { CipherView } from "jslib-common/models/view/cipherView";
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 { CollectionService } from "jslib-common/services/collection.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 { EnvironmentService } from "jslib-common/services/environment.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 { KeyConnectorService } from "jslib-common/services/keyConnector.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 { PolicyService } from "jslib-common/services/policy.service";
import { ProviderService } from "jslib-common/services/provider.service";
import { SearchService } from "jslib-common/services/search.service";
import { SendService } from "jslib-common/services/send.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 { SystemService } from "jslib-common/services/system.service";
import { TokenService } from "jslib-common/services/token.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 { 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 { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.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 { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.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 { SendService as SendServiceAbstraction } from "jslib-common/abstractions/send.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 { SyncService as SyncServiceAbstraction } from "jslib-common/abstractions/sync.service";
import { SystemService as SystemServiceAbstraction } from "jslib-common/abstractions/system.service";
import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.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 { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service";
@ -82,6 +83,8 @@ import TabsBackground from "./tabs.background";
import WebRequestBackground from "./webRequest.background";
import WindowsBackground from "./windows.background";
import { StateService as StateServiceAbstraction } from "../services/abstractions/state.service";
import { PopupUtilsService } from "../popup/services/popup-utils.service";
import AutofillService from "../services/autofill.service";
import { BrowserCryptoService } from "../services/browserCrypto.service";
@ -89,15 +92,17 @@ import BrowserMessagingService from "../services/browserMessaging.service";
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
import BrowserStorageService from "../services/browserStorage.service";
import I18nService from "../services/i18n.service";
import { StateService } from "../services/state.service";
import VaultTimeoutService from "../services/vaultTimeout.service";
import { Account } from "../models/account";
export default class MainBackground {
messagingService: MessagingServiceAbstraction;
storageService: StorageServiceAbstraction;
secureStorageService: StorageServiceAbstraction;
i18nService: I18nServiceAbstraction;
platformUtilsService: PlatformUtilsServiceAbstraction;
constantsService: ConstantsService;
logService: LogServiceAbstraction;
cryptoService: CryptoServiceAbstraction;
cryptoFunctionService: CryptoFunctionServiceAbstraction;
@ -105,7 +110,6 @@ export default class MainBackground {
appIdService: AppIdServiceAbstraction;
apiService: ApiServiceAbstraction;
environmentService: EnvironmentServiceAbstraction;
userService: UserServiceAbstraction;
settingsService: SettingsServiceAbstraction;
cipherService: CipherServiceAbstraction;
folderService: FolderServiceAbstraction;
@ -122,12 +126,15 @@ export default class MainBackground {
searchService: SearchServiceAbstraction;
notificationsService: NotificationsServiceAbstraction;
stateService: StateServiceAbstraction;
stateMigrationService: StateMigrationService;
systemService: SystemServiceAbstraction;
eventService: EventServiceAbstraction;
policyService: PolicyServiceAbstraction;
popupUtilsService: PopupUtilsService;
sendService: SendServiceAbstraction;
fileUploadService: FileUploadServiceAbstraction;
organizationService: OrganizationServiceAbstraction;
providerService: ProviderServiceAbstraction;
keyConnectorService: KeyConnectorServiceAbstraction;
userVerificationService: UserVerificationServiceAbstraction;
@ -155,9 +162,22 @@ export default class MainBackground {
// Services
this.messagingService = new BrowserMessagingService();
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.messagingService,
this.storageService,
this.stateService,
(clipboardValue, clearMs) => {
if (this.systemService != null) {
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.cryptoFunctionService = new WebCryptoFunctionService(window, this.platformUtilsService);
this.logService = new ConsoleLogService(false);
this.cryptoService = new BrowserCryptoService(
this.storageService,
this.secureStorageService,
this.cryptoFunctionService,
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.environmentService = new EnvironmentService(this.storageService);
this.environmentService = new EnvironmentService(this.stateService);
this.apiService = new ApiService(
this.tokenService,
this.platformUtilsService,
this.environmentService,
(expired: boolean) => this.logout(expired)
);
this.userService = new UserService(this.tokenService, this.storageService);
this.settingsService = new SettingsService(this.userService, this.storageService);
this.settingsService = new SettingsService(this.stateService);
this.fileUploadService = new FileUploadService(this.logService, this.apiService);
this.cipherService = new CipherService(
this.cryptoService,
this.userService,
this.settingsService,
this.apiService,
this.fileUploadService,
this.storageService,
this.i18nService,
() => this.searchService,
this.logService
this.logService,
this.stateService
);
this.folderService = new FolderService(
this.cryptoService,
this.userService,
this.apiService,
this.storageService,
this.i18nService,
this.cipherService
this.cipherService,
this.stateService
);
this.collectionService = new CollectionService(
this.cryptoService,
this.userService,
this.storageService,
this.i18nService
this.i18nService,
this.stateService
);
this.searchService = new SearchService(this.cipherService, this.logService, this.i18nService);
this.sendService = new SendService(
this.cryptoService,
this.userService,
this.apiService,
this.fileUploadService,
this.storageService,
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.storageService,
this.userService,
this.stateService,
this.cryptoService,
this.apiService,
this.tokenService,
this.logService
this.logService,
this.organizationService
);
this.vaultTimeoutService = new VaultTimeoutService(
this.cipherService,
this.folderService,
this.collectionService,
this.cryptoService,
this.platformUtilsService,
this.storageService,
this.messagingService,
this.searchService,
this.userService,
this.tokenService,
this.policyService,
this.keyConnectorService,
async () => {
const vaultTimeoutServiceCallbacks = {
locked: async () => {
if (this.notificationsService != null) {
this.notificationsService.updateConnection(false);
}
await this.setIcon();
await this.refreshBadgeAndMenu(true);
if (this.systemService != null) {
this.systemService.startProcessReload();
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.userService,
this.apiService,
this.settingsService,
this.folderService,
this.cipherService,
this.cryptoService,
this.collectionService,
this.storageService,
this.messagingService,
this.policyService,
this.sendService,
this.logService,
this.tokenService,
this.keyConnectorService,
this.stateService,
this.organizationService,
this.providerService,
async (expired: boolean) => await this.logout(expired)
);
this.eventService = new EventService(
this.storageService,
this.apiService,
this.userService,
this.cipherService,
this.logService
this.stateService,
this.logService,
this.organizationService
);
this.passwordGenerationService = new PasswordGenerationService(
this.cryptoService,
this.storageService,
this.policyService
this.policyService,
this.stateService
);
this.totpService = new TotpService(
this.storageService,
this.cryptoFunctionService,
this.logService
this.logService,
this.stateService
);
this.autofillService = new AutofillService(
this.cipherService,
this.userService,
this.stateService,
this.totpService,
this.eventService,
this.logService
@ -321,36 +343,39 @@ export default class MainBackground {
this.cryptoService
);
this.notificationsService = new NotificationsService(
this.userService,
this.syncService,
this.appIdService,
this.apiService,
this.vaultTimeoutService,
this.environmentService,
() => this.logout(true),
this.logService
this.logService,
this.stateService
);
this.popupUtilsService = new PopupUtilsService(this.platformUtilsService);
this.systemService = new SystemService(
this.storageService,
this.vaultTimeoutService,
this.messagingService,
this.platformUtilsService,
() => {
const forceWindowReload =
this.platformUtilsService.isSafari() ||
this.platformUtilsService.isFirefox() ||
this.platformUtilsService.isOpera();
BrowserApi.reloadExtension(forceWindowReload ? window : null);
return Promise.resolve();
}
);
this.userVerificationService = new UserVerificationService(
this.cryptoService,
this.i18nService,
this.apiService
);
const systemUtilsServiceReloadCallback = () => {
const forceWindowReload =
this.platformUtilsService.isSafari() ||
this.platformUtilsService.isFirefox() ||
this.platformUtilsService.isOpera();
BrowserApi.reloadExtension(forceWindowReload ? window : null);
return Promise.resolve();
};
this.systemService = new SystemService(
this.messagingService,
this.platformUtilsService,
systemUtilsServiceReloadCallback,
this.stateService
);
// Other fields
this.isSafari = this.platformUtilsService.isSafari();
this.sidebarAction = this.isSafari
@ -364,25 +389,24 @@ export default class MainBackground {
this,
this.autofillService,
this.platformUtilsService as BrowserPlatformUtilsService,
this.storageService,
this.i18nService,
this.notificationsService,
this.systemService,
this.environmentService,
this.messagingService,
this.stateService,
this.logService
);
this.nativeMessagingBackground = new NativeMessagingBackground(
this.storageService,
this.cryptoService,
this.cryptoFunctionService,
this.vaultTimeoutService,
this.runtimeBackground,
this.i18nService,
this.userService,
this.messagingService,
this.appIdService,
this.platformUtilsService
this.platformUtilsService,
this.stateService,
this.logService
);
this.commandsBackground = new CommandsBackground(
this,
@ -394,11 +418,10 @@ export default class MainBackground {
this,
this.autofillService,
this.cipherService,
this.storageService,
this.vaultTimeoutService,
this.policyService,
this.folderService,
this.userService
this.stateService
);
this.tabsBackground = new TabsBackground(this, this.notificationBackground);
@ -413,7 +436,7 @@ export default class MainBackground {
);
this.idleBackground = new IdleBackground(
this.vaultTimeoutService,
this.storageService,
this.stateService,
this.notificationsService
);
this.webRequestBackground = new WebRequestBackground(
@ -424,32 +447,35 @@ export default class MainBackground {
this.windowsBackground = new WindowsBackground(this);
const that = this;
const backgroundMessagingService = new (class extends MessagingServiceAbstraction {
// AuthService should send the messages to the background not popup.
send = (subscriber: string, arg: any = {}) => {
const message = Object.assign({}, { command: subscriber }, arg);
that.runtimeBackground.processMessage(message, that, null);
};
})();
this.authService = new AuthService(
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.
send = (subscriber: string, arg: any = {}) => {
const message = Object.assign({}, { command: subscriber }, arg);
that.runtimeBackground.processMessage(message, that, null);
};
})(),
backgroundMessagingService,
this.vaultTimeoutService,
this.logService,
this.cryptoFunctionService,
this.keyConnectorService,
this.environmentService,
this.keyConnectorService
this.stateService
);
}
async bootstrap() {
this.containerService.attachToWindow(window);
await this.stateService.init();
(this.authService as AuthService).init();
await (this.vaultTimeoutService as VaultTimeoutService).init(true);
await (this.i18nService as I18nService).init();
@ -480,7 +506,7 @@ export default class MainBackground {
return;
}
const isAuthenticated = await this.userService.isAuthenticated();
const isAuthenticated = await this.stateService.getIsAuthenticated();
const locked = await this.vaultTimeoutService.isLocked();
let suffix = "";
@ -499,9 +525,7 @@ export default class MainBackground {
return;
}
const menuDisabled = await this.storageService.get<boolean>(
ConstantsService.disableContextMenuItemKey
);
const menuDisabled = await this.stateService.getDisableContextMenuItem();
if (!menuDisabled) {
await this.buildContextMenu();
} else {
@ -520,35 +544,39 @@ export default class MainBackground {
}
}
async logout(expired: boolean) {
await this.eventService.uploadEvents();
const userId = await this.userService.getUserId();
async logout(expired: boolean, userId?: string) {
if (!userId) {
userId = await this.stateService.getUserId();
}
await this.eventService.uploadEvents(userId);
await Promise.all([
this.eventService.clearEvents(),
this.syncService.setLastSync(new Date(0)),
this.tokenService.clearToken(),
this.cryptoService.clearKeys(),
this.userService.clear(),
this.eventService.clearEvents(userId),
this.syncService.setLastSync(new Date(0), userId),
this.tokenService.clearToken(userId),
this.cryptoService.clearKeys(userId),
this.settingsService.clear(userId),
this.cipherService.clear(userId),
this.folderService.clear(userId),
this.collectionService.clear(userId),
this.policyService.clear(userId),
this.passwordGenerationService.clear(),
this.vaultTimeoutService.clear(),
this.passwordGenerationService.clear(userId),
this.vaultTimeoutService.clear(userId),
this.keyConnectorService.clear(),
]);
this.searchService.clearIndex();
this.messagingService.send("doneLoggingOut", { expired: expired });
if (userId == null || userId === (await this.stateService.getUserId())) {
this.searchService.clearIndex();
this.messagingService.send("doneLoggingOut", { expired: expired, userId: userId });
}
await this.setIcon();
await this.refreshBadgeAndMenu();
await this.reseedStorage();
this.notificationsService.updateConnection(false);
this.systemService.startProcessReload();
await this.systemService.clearPendingClipboard();
await this.reloadProcess();
}
async collectPageDetailsForContentScript(tab: any, sender: string, frameId: number = null) {
@ -591,9 +619,7 @@ export default class MainBackground {
return;
}
const currentVaultTimeout = await this.storageService.get<number>(
ConstantsService.vaultTimeoutKey
);
const currentVaultTimeout = await this.stateService.getVaultTimeout();
if (currentVaultTimeout == null) {
return;
}
@ -658,7 +684,7 @@ export default class MainBackground {
title: this.i18nService.t("copyPassword"),
});
if (await this.userService.canAccessPremium()) {
if (await this.stateService.getCanAccessPremium()) {
await this.contextMenusCreate({
type: "normal",
id: "copy-totp",
@ -718,9 +744,7 @@ export default class MainBackground {
});
}
const disableBadgeCounter = await this.storageService.get<boolean>(
ConstantsService.disableBadgeCounterKey
);
const disableBadgeCounter = await this.stateService.getDisableBadgeCounter();
let theText = "";
if (!disableBadgeCounter) {
@ -749,7 +773,7 @@ export default class MainBackground {
private async loadMenuAndUpdateBadgeForNoAccessState(contextMenuEnabled: boolean) {
if (contextMenuEnabled) {
const authed = await this.userService.isAuthenticated();
const authed = await this.stateService.getIsAuthenticated();
await this.loadNoLoginsContextMenuOptions(
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 !== ""))) {
await this.contextMenusCreate({
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 { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { ConstantsService } from "jslib-common/services/constants.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { Utils } from "jslib-common/misc/utils";
import { EncString } from "jslib-common/models/domain/encString";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { BrowserApi } from "../browser/browserApi";
@ -18,6 +18,40 @@ import RuntimeBackground from "./runtime.background";
const MessageValidTimeout = 10 * 1000;
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 {
private connected = false;
private connecting: boolean;
@ -32,18 +66,17 @@ export class NativeMessagingBackground {
private validatingFingerprint: boolean;
constructor(
private storageService: StorageService,
private cryptoService: CryptoService,
private cryptoFunctionService: CryptoFunctionService,
private vaultTimeoutService: VaultTimeoutService,
private runtimeBackground: RuntimeBackground,
private i18nService: I18nService,
private userService: UserService,
private messagingService: MessagingService,
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) {
// Reload extension to activate nativeMessaging
@ -55,7 +88,7 @@ export class NativeMessagingBackground {
async connect() {
this.appId = await this.appIdService.getAppId();
this.storageService.save(ConstantsService.biometricFingerprintValidated, false);
this.stateService.setBiometricFingerprintValidated(false);
return new Promise<void>((resolve, reject) => {
this.port = BrowserApi.connectNative("com.8bit.bitwarden");
@ -74,7 +107,7 @@ export class NativeMessagingBackground {
connectedCallback();
}
this.port.onMessage.addListener(async (message: any) => {
this.port.onMessage.addListener(async (message: ReceiveMessageOuter) => {
switch (message.command) {
case "connected":
connectedCallback();
@ -107,7 +140,7 @@ export class NativeMessagingBackground {
if (this.validatingFingerprint) {
this.validatingFingerprint = false;
this.storageService.save(ConstantsService.biometricFingerprintValidated, true);
this.stateService.setBiometricFingerprintValidated(true);
}
this.sharedSecret = new SymmetricCryptoKey(decrypted);
this.secureSetupResolve();
@ -181,25 +214,26 @@ export class NativeMessagingBackground {
});
}
async send(message: any) {
async send(message: Message) {
if (!this.connected) {
await this.connect();
}
message.userId = await this.stateService.getUserId();
message.timestamp = Date.now();
if (this.platformUtilsService.isSafari()) {
this.postMessage(message);
this.postMessage(message as any);
} else {
this.postMessage({ appId: this.appId, message: await this.encryptMessage(message) });
}
}
async encryptMessage(message: any) {
async encryptMessage(message: Message) {
if (this.sharedSecret == null) {
await this.secureCommunication();
}
message.timestamp = Date.now();
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`.
try {
this.port.postMessage(message);
} catch (e) {
// tslint:disable-next-line
console.error("NativeMessaging port disconnected, disconnecting.");
this.logService.error("NativeMessaging port disconnected, disconnecting.");
this.sharedSecret = null;
this.privateKey = null;
@ -230,21 +263,22 @@ export class NativeMessagingBackground {
}
}
private async onMessage(rawMessage: any) {
let message = rawMessage;
private async onMessage(rawMessage: ReceiveMessage | EncString) {
let message = rawMessage as ReceiveMessage;
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) {
// tslint:disable-next-line
console.error("NativeMessage is to old, ignoring.");
this.logService.error("NativeMessage is to old, ignoring.");
return;
}
switch (message.command) {
case "biometricUnlock":
await this.storageService.remove(ConstantsService.biometricAwaitingAcceptance);
await this.stateService.setBiometricAwaitingAcceptance(null);
if (message.response === "not enabled") {
this.messagingService.send("showDialog", {
@ -264,16 +298,16 @@ export class NativeMessagingBackground {
break;
}
const enabled = await this.storageService.get(ConstantsService.biometricUnlockKey);
const enabled = await this.stateService.getBiometricUnlock();
if (enabled === null || enabled === false) {
if (message.response === "unlocked") {
await this.storageService.save(ConstantsService.biometricUnlockKey, true);
await this.stateService.setBiometricUnlock(true);
}
break;
}
// Ignore unlock if already unlockeded
if (!this.vaultTimeoutService.biometricLocked) {
// Ignore unlock if already unlocked
if (!(await this.stateService.getBiometricLocked())) {
break;
}
@ -284,24 +318,25 @@ export class NativeMessagingBackground {
// Verify key is correct by attempting to decrypt a secret
try {
await this.cryptoService.getFingerprint(await this.userService.getUserId());
await this.cryptoService.getFingerprint(await this.stateService.getUserId());
} catch (e) {
// tslint:disable-next-line
console.error("Unable to verify key:", e);
this.logService.error("Unable to verify key: " + e);
await this.cryptoService.clearKey();
this.showWrongUserDialog();
message = false;
break;
// Exit early
if (this.resolver) {
this.resolver(message);
}
return;
}
this.vaultTimeoutService.biometricLocked = false;
await this.stateService.setBiometricLocked(false);
this.runtimeBackground.processMessage({ command: "unlocked" }, null, null);
}
break;
default:
// tslint:disable-next-line
console.error("NativeMessage, got unknown command: ", message.command);
this.logService.error("NativeMessage, got unknown command: " + message.command);
}
if (this.resolver) {
@ -317,13 +352,13 @@ export class NativeMessagingBackground {
this.sendUnencrypted({
command: "setupEncryption",
publicKey: Utils.fromBufferToB64(publicKey),
userId: await this.userService.getUserId(),
userId: await this.stateService.getUserId(),
});
return new Promise((resolve, reject) => (this.secureSetupResolve = resolve));
}
private async sendUnencrypted(message: any) {
private async sendUnencrypted(message: Message) {
if (!this.connected) {
await this.connect();
}
@ -335,7 +370,7 @@ export class NativeMessagingBackground {
private async showFingerprintDialog() {
const fingerprint = (
await this.cryptoService.getFingerprint(await this.userService.getUserId(), this.publicKey)
await this.cryptoService.getFingerprint(await this.stateService.getUserId(), this.publicKey)
).join(" ");
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 { FolderService } from "jslib-common/abstractions/folder.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 { ConstantsService } from "jslib-common/services/constants.service";
import { AutofillService } from "../services/abstractions/autofill.service";
import { BrowserApi } from "../browser/browserApi";
@ -23,6 +19,7 @@ import { Utils } from "jslib-common/misc/utils";
import { PolicyType } from "jslib-common/enums/policyType";
import { StateService } from "../services/abstractions/state.service";
import AddChangePasswordQueueMessage from "./models/addChangePasswordQueueMessage";
import AddLoginQueueMessage from "./models/addLoginQueueMessage";
import AddLoginRuntimeMessage from "./models/addLoginRuntimeMessage";
@ -37,11 +34,10 @@ export default class NotificationBackground {
private main: MainBackground,
private autofillService: AutofillService,
private cipherService: CipherService,
private storageService: StorageService,
private vaultTimeoutService: VaultTimeoutService,
private policyService: PolicyService,
private folderService: FolderService,
private userService: UserService
private stateService: StateService
) {}
async init() {
@ -198,7 +194,7 @@ export default class NotificationBackground {
}
private async addLogin(loginInfo: AddLoginRuntimeMessage, tab: chrome.tabs.Tab) {
if (!(await this.userService.isAuthenticated())) {
if (!(await this.stateService.getIsAuthenticated())) {
return;
}
@ -212,9 +208,7 @@ export default class NotificationBackground {
normalizedUsername = normalizedUsername.toLowerCase();
}
const disabledAddLogin = await this.storageService.get<boolean>(
ConstantsService.disableAddLoginNotificationKey
);
const disabledAddLogin = await this.stateService.getDisableAddLoginNotification();
if (await this.vaultTimeoutService.isLocked()) {
if (disabledAddLogin) {
return;
@ -246,9 +240,8 @@ export default class NotificationBackground {
usernameMatches.length === 1 &&
usernameMatches[0].login.password !== loginInfo.password
) {
const disabledChangePassword = await this.storageService.get<boolean>(
ConstantsService.disableChangedPasswordNotificationKey
);
const disabledChangePassword =
await this.stateService.getDisableChangedPasswordNotification();
if (disabledChangePassword) {
return;
}

View File

@ -3,9 +3,8 @@ 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 { 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 { ConstantsService } from "jslib-common/services/constants.service";
import { AutofillService } from "../services/abstractions/autofill.service";
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
@ -27,12 +26,12 @@ export default class RuntimeBackground {
private main: MainBackground,
private autofillService: AutofillService,
private platformUtilsService: BrowserPlatformUtilsService,
private storageService: StorageService,
private i18nService: I18nService,
private notificationsService: NotificationsService,
private systemService: SystemService,
private environmentService: EnvironmentService,
private messagingService: MessagingService,
private stateService: StateService,
private logService: LogService
) {
// 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);
break;
case "logout":
await this.main.logout(msg.expired);
await this.main.logout(msg.expired, msg.userId);
break;
case "syncCompleted":
if (msg.successfully) {
@ -220,29 +219,10 @@ export default class RuntimeBackground {
if (this.onInstalledReason != null) {
if (this.onInstalledReason === "install") {
BrowserApi.createNewTab("https://bitwarden.com/browser-start/");
await this.setDefaultSettings();
}
this.onInstalledReason = null;
}
}, 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 { ConstantsService } from "jslib-common/services/constants.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.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";
@ -18,7 +16,7 @@ export class HomeComponent {
constructor(
protected platformUtilsService: PlatformUtilsService,
private passwordGenerationService: PasswordGenerationService,
private storageService: StorageService,
private stateService: StateService,
private cryptoFunctionService: CryptoFunctionService,
private environmentService: EnvironmentService
) {}
@ -41,8 +39,8 @@ export class HomeComponent {
const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, "sha256");
const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
await this.storageService.save(ConstantsService.ssoCodeVerifierKey, codeVerifier);
await this.storageService.save(ConstantsService.ssoStateKey, state);
await this.stateService.setSsoCodeVerifier(codeVerifier);
await this.stateService.setSsoState(state);
let url = this.environmentService.getWebVaultUrl();
if (url == null) {

View File

@ -2,8 +2,6 @@ import { Component, NgZone } from "@angular/core";
import { Router } from "@angular/router";
import Swal from "sweetalert2";
import { ConstantsService } from "jslib-common/services/constants.service";
import { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoService } from "jslib-common/abstractions/crypto.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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { LockComponent as BaseLockComponent } from "jslib-angular/components/lock.component";
@ -31,9 +27,7 @@ export class LockComponent extends BaseLockComponent {
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,
messagingService: MessagingService,
userService: UserService,
cryptoService: CryptoService,
storageService: StorageService,
vaultTimeoutService: VaultTimeoutService,
environmentService: EnvironmentService,
stateService: StateService,
@ -47,9 +41,7 @@ export class LockComponent extends BaseLockComponent {
i18nService,
platformUtilsService,
messagingService,
userService,
cryptoService,
storageService,
vaultTimeoutService,
environmentService,
stateService,
@ -65,8 +57,7 @@ export class LockComponent extends BaseLockComponent {
async ngOnInit() {
await super.ngOnInit();
const disableAutoBiometricsPrompt =
(await this.storageService.get<boolean>(ConstantsService.disableAutoBiometricsPromptKey)) ??
true;
(await this.stateService.getDisableAutoBiometricsPrompt()) ?? true;
window.setTimeout(async () => {
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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { 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",
})
export class LoginComponent extends BaseLoginComponent {
protected alwaysRememberEmail: boolean = true;
constructor(
authService: AuthService,
router: Router,
@ -28,7 +29,6 @@ export class LoginComponent extends BaseLoginComponent {
protected environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationService,
protected cryptoFunctionService: CryptoFunctionService,
storageService: StorageService,
syncService: SyncService,
logService: LogService,
ngZone: NgZone
@ -42,7 +42,6 @@ export class LoginComponent extends BaseLoginComponent {
environmentService,
passwordGenerationService,
cryptoFunctionService,
storageService,
logService,
ngZone
);

View File

@ -9,8 +9,8 @@ import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { UserService } from "jslib-common/abstractions/user.service";
import { SetPasswordComponent as BaseSetPasswordComponent } from "jslib-angular/components/set-password.component";
@ -24,7 +24,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
i18nService: I18nService,
cryptoService: CryptoService,
messagingService: MessagingService,
userService: UserService,
stateService: StateService,
passwordGenerationService: PasswordGenerationService,
platformUtilsService: PlatformUtilsService,
policyService: PolicyService,
@ -36,14 +36,14 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
i18nService,
cryptoService,
messagingService,
userService,
passwordGenerationService,
platformUtilsService,
policyService,
router,
apiService,
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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
@ -28,7 +27,6 @@ export class SsoComponent extends BaseSsoComponent {
router: Router,
i18nService: I18nService,
route: ActivatedRoute,
storageService: StorageService,
stateService: StateService,
platformUtilsService: PlatformUtilsService,
apiService: ApiService,
@ -44,7 +42,6 @@ export class SsoComponent extends BaseSsoComponent {
router,
i18nService,
route,
storageService,
stateService,
platformUtilsService,
apiService,

View File

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

View File

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

View File

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

View File

@ -29,7 +29,7 @@ export class PasswordGeneratorComponent extends BasePasswordGeneratorComponent {
async ngOnInit() {
await super.ngOnInit();
const addEditCipherInfo = await this.stateService.get<any>("addEditCipherInfo");
const addEditCipherInfo = await this.stateService.getAddEditCipherInfo();
if (addEditCipherInfo != null) {
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 { PolicyService } from "jslib-common/abstractions/policy.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";
@ -36,7 +37,7 @@ export class SendAddEditComponent extends BaseAddEditComponent {
constructor(
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,
userService: UserService,
stateService: StateService,
messagingService: MessagingService,
policyService: PolicyService,
environmentService: EnvironmentService,
@ -54,10 +55,10 @@ export class SendAddEditComponent extends BaseAddEditComponent {
environmentService,
datePipe,
sendService,
userService,
messagingService,
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 { SearchService } from "jslib-common/abstractions/search.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 { UserService } from "jslib-common/abstractions/user.service";
import { StateService } from "../../services/abstractions/state.service";
import { PopupUtilsService } from "../services/popup-utils.service";
import { SendType } from "jslib-common/enums/sendType";
import { BrowserSendComponentState } from "src/models/browserSendComponentState";
const ComponentId = "SendComponent";
const ScopeStateId = ComponentId + "Scope";
@Component({
selector: "app-send-groupings",
@ -35,8 +35,7 @@ export class SendGroupingsComponent extends BaseSendComponent {
// Send Type Calculations
typeCounts = new Map<SendType, number>();
// State Handling
state: any;
scopeState: any;
state: BrowserSendComponentState;
private loadedTimeout: number;
constructor(
@ -46,7 +45,6 @@ export class SendGroupingsComponent extends BaseSendComponent {
environmentService: EnvironmentService,
ngZone: NgZone,
policyService: PolicyService,
userService: UserService,
searchService: SearchService,
private popupUtils: PopupUtilsService,
private stateService: StateService,
@ -64,7 +62,6 @@ export class SendGroupingsComponent extends BaseSendComponent {
ngZone,
searchService,
policyService,
userService,
logService
);
super.onSuccessfulLoad = async () => {
@ -79,13 +76,12 @@ export class SendGroupingsComponent extends BaseSendComponent {
this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
);
// Clear state of Send Type Component
this.stateService.remove("SendTypeComponent");
await this.stateService.setBrowserSendTypeComponentState(null);
// Let super class finish
await super.ngOnInit();
// Handle State Restore if necessary
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;
}
@ -100,7 +96,7 @@ export class SendGroupingsComponent extends BaseSendComponent {
}
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
@ -177,27 +173,23 @@ export class SendGroupingsComponent extends BaseSendComponent {
this.state = {
scrollY: this.popupUtils.getContentScrollY(window),
searchText: this.searchText,
};
await this.stateService.save(ComponentId, this.state);
this.scopeState = {
sends: this.sends,
typeCounts: this.typeCounts,
};
await this.stateService.save(ScopeStateId, this.scopeState);
await this.stateService.setBrowserSendComponentState(this.state);
}
private async restoreState(): Promise<boolean> {
this.scopeState = await this.stateService.get<any>(ScopeStateId);
if (this.scopeState == null) {
this.state = await this.stateService.getBrowserSendComponentState();
if (this.state == null) {
return false;
}
if (this.scopeState.sends != null) {
this.sends = this.scopeState.sends;
if (this.state.sends != null) {
this.sends = this.state.sends;
}
if (this.scopeState.typeCounts != null) {
this.typeCounts = this.scopeState.typeCounts;
if (this.state.typeCounts != null) {
this.typeCounts = this.state.typeCounts;
}
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 { SearchService } from "jslib-common/abstractions/search.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 { SendType } from "jslib-common/enums/sendType";
import { BrowserComponentState } from "../../models/browserComponentState";
const ComponentId = "SendTypeComponent";
@Component({
@ -34,7 +35,7 @@ const ComponentId = "SendTypeComponent";
export class SendTypeComponent extends BaseSendComponent {
groupingTitle: string;
// State Handling
state: any;
state: BrowserComponentState;
private refreshTimeout: number;
private applySavedState = true;
@ -45,7 +46,6 @@ export class SendTypeComponent extends BaseSendComponent {
environmentService: EnvironmentService,
ngZone: NgZone,
policyService: PolicyService,
userService: UserService,
searchService: SearchService,
private popupUtils: PopupUtilsService,
private stateService: StateService,
@ -64,7 +64,6 @@ export class SendTypeComponent extends BaseSendComponent {
ngZone,
searchService,
policyService,
userService,
logService
);
super.onSuccessfulLoad = async () => {
@ -80,8 +79,8 @@ export class SendTypeComponent extends BaseSendComponent {
await super.ngOnInit();
this.route.queryParams.pipe(first()).subscribe(async (params) => {
if (this.applySavedState) {
this.state = (await this.stateService.get<any>(ComponentId)) || {};
if (this.state.searchText != null) {
this.state = await this.stateService.getBrowserSendTypeComponentState();
if (this.state?.searchText != null) {
this.searchText = this.state.searchText;
}
}
@ -103,9 +102,9 @@ export class SendTypeComponent extends BaseSendComponent {
// Restore state and remove reference
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
@ -167,6 +166,6 @@ export class SendTypeComponent extends BaseSendComponent {
scrollY: this.popupUtils.getContentScrollY(window),
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 { MessagingService } from "jslib-common/abstractions/messaging.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 { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { SendService } from "jslib-common/abstractions/send.service";
import { SettingsService } from "jslib-common/abstractions/settings.service";
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { StateService as BaseStateServiceAbstraction } from "jslib-common/abstractions/state.service";
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
import { SyncService } from "jslib-common/abstractions/sync.service";
import { TokenService } from "jslib-common/abstractions/token.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 { 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 { ConsoleLogService } from "jslib-common/services/consoleLog.service";
import { ConstantsService } from "jslib-common/services/constants.service";
import { SearchService } from "jslib-common/services/search.service";
import { StateService } from "jslib-common/services/state.service";
import { PopupSearchService } from "./popup-search.service";
import { PopupUtilsService } from "./popup-utils.service";
import { ThemeType } from "jslib-common/enums/themeType";
import { StateService as StateServiceAbstraction } from "../../services/abstractions/state.service";
function getBgService<T>(service: string) {
return (): T => {
const page = BrowserApi.getBackgroundPage();
@ -72,12 +73,13 @@ const isPrivateMode = BrowserApi.getBackgroundPage() == null;
export function initFactory(
platformUtilsService: PlatformUtilsService,
i18nService: I18nService,
storageService: StorageService,
popupUtilsService: PopupUtilsService,
stateService: StateServiceAbstraction,
logService: LogServiceAbstraction
): Function {
return async () => {
await stateService.init();
if (!popupUtilsService.inPopup(window)) {
window.document.body.classList.add("body-full");
} else if (window.screen.availHeight < 600) {
@ -87,21 +89,11 @@ export function initFactory(
}
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 theme = await platformUtilsService.getEffectiveTheme();
htmlEl.classList.add("theme_" + theme);
platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => {
const bwTheme = await storageService.get<ThemeType>(ConstantsService.themeKey);
const bwTheme = await stateService.getTheme();
if (bwTheme == null || bwTheme === ThemeType.System) {
htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark);
htmlEl.classList.add("theme_" + sysTheme);
@ -143,7 +135,6 @@ export function initFactory(
deps: [
PlatformUtilsService,
I18nService,
StorageService,
PopupUtilsService,
StateServiceAbstraction,
LogServiceAbstraction,
@ -161,7 +152,6 @@ export function initFactory(
useFactory: getBgService<AuthService>("authService"),
deps: [],
},
{ provide: StateServiceAbstraction, useClass: StateService },
{
provide: SearchServiceAbstraction,
useFactory: (
@ -226,15 +216,14 @@ export function initFactory(
},
{ provide: ApiService, useFactory: getBgService<ApiService>("apiService"), deps: [] },
{ provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] },
{ provide: UserService, useFactory: getBgService<UserService>("userService"), deps: [] },
{
provide: SettingsService,
useFactory: getBgService<SettingsService>("settingsService"),
deps: [],
},
{
provide: StorageService,
useFactory: getBgService<StorageService>("storageService"),
provide: StorageServiceAbstraction,
useFactory: getBgService<StorageServiceAbstraction>("storageService"),
deps: [],
},
{ provide: AppIdService, useFactory: getBgService<AppIdService>("appIdService"), deps: [] },
@ -271,6 +260,31 @@ export function initFactory(
deps: [],
},
{ 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 {}

View File

@ -2,12 +2,10 @@ import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { ConstantsService } from "jslib-common/services/constants.service";
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
import { I18nService } from "jslib-common/abstractions/i18n.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";
@ -30,7 +28,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
loadCurrentUrisTimeout: number;
constructor(
private storageService: StorageService,
private stateService: StateService,
private i18nService: I18nService,
private router: Router,
private broadcasterService: BroadcasterService,
@ -39,7 +37,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
) {}
async ngOnInit() {
const savedDomains = await this.storageService.get<any>(ConstantsService.neverDomainsKey);
const savedDomains = await this.stateService.getNeverDomains();
if (savedDomains) {
for (const uri of Object.keys(savedDomains)) {
this.excludedDomains.push({ uri: uri, showCurrentUris: false });
@ -96,7 +94,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy {
savedDomains[validDomain] = null;
}
}
await this.storageService.save(ConstantsService.neverDomainsKey, savedDomains);
await this.stateService.setNeverDomains(savedDomains);
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 { MessagingService } from "jslib-common/abstractions/messaging.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 { ConstantsService } from "jslib-common/services/constants.service";
@Component({
selector: "app-options",
templateUrl: "options.component.html",
@ -40,7 +37,6 @@ export class OptionsComponent implements OnInit {
constructor(
private messagingService: MessagingService,
private storageService: StorageService,
private stateService: StateService,
private totpService: TotpService,
i18nService: I18nService
@ -76,136 +72,89 @@ export class OptionsComponent implements OnInit {
}
async ngOnInit() {
this.enableAutoFillOnPageLoad = await this.storageService.get<boolean>(
ConstantsService.enableAutoFillOnPageLoadKey
);
this.enableAutoFillOnPageLoad = await this.stateService.getEnableAutoFillOnPageLoad();
this.autoFillOnPageLoadDefault =
(await this.storageService.get<boolean>(ConstantsService.autoFillOnPageLoadDefaultKey)) ??
true;
(await this.stateService.getAutoFillOnPageLoadDefault()) ?? true;
this.disableAddLoginNotification = await this.storageService.get<boolean>(
ConstantsService.disableAddLoginNotificationKey
);
this.disableAddLoginNotification = await this.stateService.getDisableAddLoginNotification();
this.disableChangedPasswordNotification = await this.storageService.get<boolean>(
ConstantsService.disableChangedPasswordNotificationKey
);
this.disableChangedPasswordNotification =
await this.stateService.getDisableChangedPasswordNotification();
this.disableContextMenuItem = await this.storageService.get<boolean>(
ConstantsService.disableContextMenuItemKey
);
this.disableContextMenuItem = await this.stateService.getDisableContextMenuItem();
this.dontShowCards = await this.storageService.get<boolean>(
ConstantsService.dontShowCardsCurrentTab
);
this.dontShowIdentities = await this.storageService.get<boolean>(
ConstantsService.dontShowIdentitiesCurrentTab
);
this.dontShowCards = await this.stateService.getDontShowCardsCurrentTab();
this.dontShowIdentities = await this.stateService.getDontShowIdentitiesCurrentTab();
this.disableAutoTotpCopy = !(await this.totpService.isAutoCopyEnabled());
this.disableFavicon = await this.storageService.get<boolean>(
ConstantsService.disableFaviconKey
);
this.disableFavicon = await this.stateService.getDisableFavicon();
this.disableBadgeCounter = await this.storageService.get<boolean>(
ConstantsService.disableBadgeCounterKey
);
this.disableBadgeCounter = await this.stateService.getDisableBadgeCounter();
this.theme = await this.storageService.get<string>(ConstantsService.themeKey);
this.theme = await this.stateService.getTheme();
const defaultUriMatch = await this.storageService.get<UriMatchType>(
ConstantsService.defaultUriMatch
);
const defaultUriMatch = await this.stateService.getDefaultUriMatch();
this.defaultUriMatch = defaultUriMatch == null ? UriMatchType.Domain : defaultUriMatch;
this.clearClipboard = await this.storageService.get<number>(ConstantsService.clearClipboardKey);
this.clearClipboard = await this.stateService.getClearClipboard();
}
async updateAddLoginNotification() {
await this.storageService.save(
ConstantsService.disableAddLoginNotificationKey,
this.disableAddLoginNotification
);
await this.stateService.setDisableAddLoginNotification(this.disableAddLoginNotification);
}
async updateChangedPasswordNotification() {
await this.storageService.save(
ConstantsService.disableChangedPasswordNotificationKey,
await this.stateService.setDisableChangedPasswordNotification(
this.disableChangedPasswordNotification
);
}
async updateDisableContextMenuItem() {
await this.storageService.save(
ConstantsService.disableContextMenuItemKey,
this.disableContextMenuItem
);
await this.stateService.setDisableContextMenuItem(this.disableContextMenuItem);
this.messagingService.send("bgUpdateContextMenu");
}
async updateAutoTotpCopy() {
await this.storageService.save(
ConstantsService.disableAutoTotpCopyKey,
this.disableAutoTotpCopy
);
await this.stateService.setDisableAutoTotpCopy(this.disableAutoTotpCopy);
}
async updateAutoFillOnPageLoad() {
await this.storageService.save(
ConstantsService.enableAutoFillOnPageLoadKey,
this.enableAutoFillOnPageLoad
);
await this.stateService.setEnableAutoFillOnPageLoad(this.enableAutoFillOnPageLoad);
}
async updateAutoFillOnPageLoadDefault() {
await this.storageService.save(
ConstantsService.autoFillOnPageLoadDefaultKey,
this.autoFillOnPageLoadDefault
);
await this.stateService.setAutoFillOnPageLoadDefault(this.autoFillOnPageLoadDefault);
}
async updateDisableFavicon() {
await this.storageService.save(ConstantsService.disableFaviconKey, this.disableFavicon);
await this.stateService.save(ConstantsService.disableFaviconKey, this.disableFavicon);
await this.stateService.setDisableFavicon(this.disableFavicon);
}
async updateDisableBadgeCounter() {
await this.storageService.save(
ConstantsService.disableBadgeCounterKey,
this.disableBadgeCounter
);
await this.stateService.save(ConstantsService.disableBadgeCounterKey, this.disableBadgeCounter);
await this.stateService.setDisableBadgeCounter(this.disableBadgeCounter);
this.messagingService.send("bgUpdateContextMenu");
}
async updateShowCards() {
await this.storageService.save(ConstantsService.dontShowCardsCurrentTab, this.dontShowCards);
await this.stateService.save(ConstantsService.dontShowCardsCurrentTab, this.dontShowCards);
await this.stateService.setDontShowCardsCurrentTab(this.dontShowCards);
}
async updateShowIdentities() {
await this.storageService.save(
ConstantsService.dontShowIdentitiesCurrentTab,
this.dontShowIdentities
);
await this.stateService.save(
ConstantsService.dontShowIdentitiesCurrentTab,
this.dontShowIdentities
);
await this.stateService.setDontShowIdentitiesCurrentTab(this.dontShowIdentities);
}
async saveTheme() {
await this.storageService.save(ConstantsService.themeKey, this.theme);
await this.stateService.setTheme(this.theme);
window.setTimeout(() => window.location.reload(), 200);
}
async saveDefaultUriMatch() {
await this.storageService.save(ConstantsService.defaultUriMatch, this.defaultUriMatch);
await this.stateService.setDefaultUriMatch(this.defaultUriMatch);
}
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 { LogService } from "jslib-common/abstractions/log.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";
@ -20,11 +20,11 @@ export class PremiumComponent extends BasePremiumComponent {
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,
apiService: ApiService,
userService: UserService,
private currencyPipe: CurrencyPipe,
logService: LogService
stateService: StateService,
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.
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 { ConstantsService } from "jslib-common/services/constants.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
import { PopupUtilsService } from "../services/popup-utils.service";
@ -61,12 +58,11 @@ export class SettingsComponent implements OnInit {
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private vaultTimeoutService: VaultTimeoutService,
private storageService: StorageService,
public messagingService: MessagingService,
private router: Router,
private environmentService: EnvironmentService,
private cryptoService: CryptoService,
private userService: UserService,
private stateService: StateService,
private popupUtilsService: PopupUtilsService,
private modalService: ModalService,
private keyConnectorService: KeyConnectorService
@ -112,7 +108,7 @@ export class SettingsComponent implements OnInit {
this.saveVaultTimeout(value);
});
const action = await this.storageService.get<string>(ConstantsService.vaultTimeoutActionKey);
const action = await this.stateService.getVaultTimeoutAction();
this.vaultTimeoutAction = action == null ? "lock" : action;
const pinSet = await this.vaultTimeoutService.isPinLockSet();
@ -121,8 +117,7 @@ export class SettingsComponent implements OnInit {
this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
this.biometric = await this.vaultTimeoutService.isBiometricLockSet();
this.disableAutoBiometricsPrompt =
(await this.storageService.get<boolean>(ConstantsService.disableAutoBiometricsPromptKey)) ??
true;
(await this.stateService.getDisableAutoBiometricsPrompt()) ?? true;
this.showChangeMasterPass = !(await this.keyConnectorService.getUsesKeyConnector());
}
@ -250,14 +245,14 @@ export class SettingsComponent implements OnInit {
allowOutsideClick: false,
});
await this.storageService.save(ConstantsService.biometricAwaitingAcceptance, true);
await this.stateService.setBiometricAwaitingAcceptance(true);
await this.cryptoService.toggleKey();
await Promise.race([
submitted.then((result) => {
submitted.then(async (result) => {
if (result.dismiss === Swal.DismissReason.cancel) {
this.biometric = false;
this.storageService.remove(ConstantsService.biometricAwaitingAcceptance);
await this.stateService.setBiometricAwaitingAcceptance(null);
}
}),
this.platformUtilsService
@ -280,16 +275,13 @@ export class SettingsComponent implements OnInit {
}),
]);
} else {
await this.storageService.remove(ConstantsService.biometricUnlockKey);
this.vaultTimeoutService.biometricLocked = false;
await this.stateService.setBiometricUnlock(null);
await this.stateService.setBiometricLocked(false);
}
}
async updateAutoBiometricsPrompt() {
await this.storageService.save(
ConstantsService.disableAutoBiometricsPromptKey,
this.disableAutoBiometricsPrompt
);
await this.stateService.setDisableAutoBiometricsPrompt(this.disableAutoBiometricsPrompt);
}
async lock() {
@ -385,7 +377,9 @@ export class SettingsComponent implements OnInit {
}
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");
p.innerText = this.i18nService.t("yourAccountsFingerprint") + ":";
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 { LogService } from "jslib-common/abstractions/log.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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.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";
@ -48,7 +45,6 @@ export class AddEditComponent extends BaseAddEditComponent {
platformUtilsService: PlatformUtilsService,
auditService: AuditService,
stateService: StateService,
userService: UserService,
collectionService: CollectionService,
messagingService: MessagingService,
private route: ActivatedRoute,
@ -57,9 +53,9 @@ export class AddEditComponent extends BaseAddEditComponent {
eventService: EventService,
policyService: PolicyService,
private popupUtilsService: PopupUtilsService,
private storageService: StorageService,
logService: LogService,
passwordRepromptService: PasswordRepromptService
organizationService: OrganizationService,
passwordRepromptService: PasswordRepromptService,
logService: LogService
) {
super(
cipherService,
@ -68,13 +64,13 @@ export class AddEditComponent extends BaseAddEditComponent {
platformUtilsService,
auditService,
stateService,
userService,
collectionService,
messagingService,
eventService,
policyService,
logService,
passwordRepromptService,
logService
organizationService
);
}
@ -149,7 +145,7 @@ export class AddEditComponent extends BaseAddEditComponent {
await super.load();
this.showAutoFillOnPageLoadOptions =
this.cipher.type === CipherType.Login &&
(await this.storageService.get<boolean>(ConstantsService.enableAutoFillOnPageLoadKey));
(await this.stateService.getEnableAutoFillOnPageLoad());
}
async submit(): Promise<boolean> {
@ -194,7 +190,7 @@ export class AddEditComponent extends BaseAddEditComponent {
async generatePassword(): Promise<boolean> {
const confirmed = await super.generatePassword();
if (confirmed) {
this.stateService.save("addEditCipherInfo", {
this.stateService.setAddEditCipherInfo({
cipher: this.cipher,
collectionIds:
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 { LogService } from "jslib-common/abstractions/log.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";
@ -25,22 +25,22 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
cipherService: CipherService,
i18nService: I18nService,
cryptoService: CryptoService,
userService: UserService,
platformUtilsService: PlatformUtilsService,
apiService: ApiService,
private location: Location,
private route: ActivatedRoute,
stateService: StateService,
logService: LogService
) {
super(
cipherService,
i18nService,
cryptoService,
userService,
platformUtilsService,
apiService,
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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { TreeNode } from "jslib-common/models/domain/treeNode";
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 { TreeNode } from "jslib-common/models/domain/treeNode";
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";
const ComponentId = "CiphersComponent";
@ -35,7 +36,7 @@ const ComponentId = "CiphersComponent";
})
export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy {
groupingTitle: string;
state: any;
state: BrowserComponentState;
folderId: string = null;
collectionId: string = null;
type: CipherType = null;
@ -74,8 +75,8 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
this.searchTypeSearch = !this.platformUtilsService.isSafari();
this.route.queryParams.pipe(first()).subscribe(async (params) => {
if (this.applySavedState) {
this.state = (await this.stateService.get<any>(ComponentId)) || {};
if (this.state.searchText) {
this.state = await this.stateService.getBrowserCipherComponentState();
if (this.state?.searchText) {
this.searchText = this.state.searchText;
}
}
@ -146,7 +147,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
0
);
}
this.stateService.remove(ComponentId);
await this.stateService.setBrowserCipherComponentState(null);
});
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),
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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { ConstantsService } from "jslib-common/services/constants.service";
import { AutofillService } from "../../services/abstractions/autofill.service";
import { PopupUtilsService } from "../services/popup-utils.service";
@ -60,7 +58,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
private changeDetectorRef: ChangeDetectorRef,
private syncService: SyncService,
private searchService: SearchService,
private storageService: StorageService,
private stateService: StateService,
private passwordRepromptService: PasswordRepromptService
) {}
@ -209,12 +207,8 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
});
const otherTypes: CipherType[] = [];
const dontShowCards = await this.storageService.get<boolean>(
ConstantsService.dontShowCardsCurrentTab
);
const dontShowIdentities = await this.storageService.get<boolean>(
ConstantsService.dontShowIdentitiesCurrentTab
);
const dontShowCards = await this.stateService.getDontShowCardsCurrentTab();
const dontShowIdentities = await this.stateService.getDontShowIdentitiesCurrentTab();
if (!dontShowCards) {
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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.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 { UserService } from "jslib-common/abstractions/user.service";
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 { BrowserGroupingsComponentState } from "src/models/browserGroupingsComponentState";
const ComponentId = "GroupingsComponent";
const ScopeStateId = ComponentId + "Scope";
@Component({
selector: "app-vault-groupings",
@ -53,8 +53,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
collectionCounts = new Map<string, number>();
typeCounts = new Map<CipherType, number>();
searchText: string;
state: any;
scopeState: any;
state: BrowserGroupingsComponentState;
showLeftHeader = true;
searchPending = false;
searchTypeSearch = false;
@ -72,22 +71,20 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
constructor(
collectionService: CollectionService,
folderService: FolderService,
storageService: StorageService,
userService: UserService,
private cipherService: CipherService,
private router: Router,
private ngZone: NgZone,
private broadcasterService: BroadcasterService,
private changeDetectorRef: ChangeDetectorRef,
private route: ActivatedRoute,
private stateService: StateService,
private popupUtils: PopupUtilsService,
private syncService: SyncService,
private platformUtilsService: PlatformUtilsService,
private searchService: SearchService,
private location: Location
private location: Location,
private browserStateService: StateService
) {
super(collectionService, folderService, storageService, userService);
super(collectionService, folderService, browserStateService);
this.noFolderListSize = 100;
}
@ -96,7 +93,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
this.showLeftHeader = !(
this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()
);
this.stateService.remove("CiphersComponent");
await this.browserStateService.setBrowserCipherComponentState(null);
this.broadcasterService.subscribe(ComponentId, (message: any) => {
this.ngZone.run(async () => {
@ -116,8 +113,8 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
const restoredScopeState = await this.restoreState();
this.route.queryParams.pipe(first()).subscribe(async (params) => {
this.state = (await this.stateService.get<any>(ComponentId)) || {};
if (this.state.searchText) {
this.state = await this.browserStateService.getBrowserGroupingComponentState();
if (this.state?.searchText) {
this.searchText = this.state.searchText;
} else if (params.searchText) {
this.searchText = params.searchText;
@ -135,7 +132,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
}
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 = {
scrollY: this.popupUtils.getContentScrollY(window),
searchText: this.searchText,
};
await this.stateService.save(ComponentId, this.state);
this.scopeState = {
favoriteCiphers: this.favoriteCiphers,
noFolderCiphers: this.noFolderCiphers,
ciphers: this.ciphers,
@ -334,41 +327,41 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
collections: this.collections,
deletedCount: this.deletedCount,
};
await this.stateService.save(ScopeStateId, this.scopeState);
await this.browserStateService.setBrowserGroupingComponentState(this.state);
}
private async restoreState(): Promise<boolean> {
this.scopeState = await this.stateService.get<any>(ScopeStateId);
if (this.scopeState == null) {
this.state = await this.browserStateService.getBrowserGroupingComponentState();
if (this.state == null) {
return false;
}
if (this.scopeState.favoriteCiphers != null) {
this.favoriteCiphers = this.scopeState.favoriteCiphers;
if (this.state.favoriteCiphers != null) {
this.favoriteCiphers = this.state.favoriteCiphers;
}
if (this.scopeState.noFolderCiphers != null) {
this.noFolderCiphers = this.scopeState.noFolderCiphers;
if (this.state.noFolderCiphers != null) {
this.noFolderCiphers = this.state.noFolderCiphers;
}
if (this.scopeState.ciphers != null) {
this.ciphers = this.scopeState.ciphers;
if (this.state.ciphers != null) {
this.ciphers = this.state.ciphers;
}
if (this.scopeState.collectionCounts != null) {
this.collectionCounts = this.scopeState.collectionCounts;
if (this.state.collectionCounts != null) {
this.collectionCounts = this.state.collectionCounts;
}
if (this.scopeState.folderCounts != null) {
this.folderCounts = this.scopeState.folderCounts;
if (this.state.folderCounts != null) {
this.folderCounts = this.state.folderCounts;
}
if (this.scopeState.typeCounts != null) {
this.typeCounts = this.scopeState.typeCounts;
if (this.state.typeCounts != null) {
this.typeCounts = this.state.typeCounts;
}
if (this.scopeState.folders != null) {
this.folders = this.scopeState.folders;
if (this.state.folders != null) {
this.folders = this.state.folders;
}
if (this.scopeState.collections != null) {
this.collections = this.scopeState.collections;
if (this.state.collections != null) {
this.collections = this.state.collections;
}
if (this.scopeState.deletedCiphers != null) {
this.deletedCount = this.scopeState.deletedCount;
if (this.state.deletedCount != null) {
this.deletedCount = this.state.deletedCount;
}
return true;

View File

@ -1,4 +1,3 @@
import { Location } from "@angular/common";
import { Component } from "@angular/core";
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 { I18nService } from "jslib-common/abstractions/i18n.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 { UserService } from "jslib-common/abstractions/user.service";
import { ShareComponent as BaseShareComponent } from "jslib-angular/components/share.component";
@ -22,19 +21,19 @@ export class ShareComponent extends BaseShareComponent {
collectionService: CollectionService,
platformUtilsService: PlatformUtilsService,
i18nService: I18nService,
userService: UserService,
logService: LogService,
cipherService: CipherService,
private route: ActivatedRoute,
private router: Router,
logService: LogService
organizationService: OrganizationService
) {
super(
collectionService,
platformUtilsService,
i18nService,
userService,
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 { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.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 { TotpService } from "jslib-common/abstractions/totp.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { Cipher } from "jslib-common/models/domain/cipher";
import { LoginUriView } from "jslib-common/models/view/loginUriView";
@ -57,7 +57,7 @@ export class ViewComponent extends BaseViewComponent {
broadcasterService: BroadcasterService,
ngZone: NgZone,
changeDetectorRef: ChangeDetectorRef,
userService: UserService,
stateService: StateService,
eventService: EventService,
private autofillService: AutofillService,
private messagingService: MessagingService,
@ -78,11 +78,11 @@ export class ViewComponent extends BaseViewComponent {
broadcasterService,
ngZone,
changeDetectorRef,
userService,
eventService,
apiService,
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
if success {
let passwordName = "key"
guard let userId = message?["userId"] as? String else {
return
}
let passwordName = userId + "_masterkey_biometric"
var passwordLength: UInt32 = 0
var passwordPtr: UnsafeMutableRawPointer? = nil
var status = SecKeychainFindGenericPassword(nil, UInt32(ServiceNameBiometric.utf8.count), ServiceNameBiometric, UInt32(passwordName.utf8.count), passwordName, &passwordLength, &passwordPtr, nil)
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 {

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 { LogService } from "jslib-common/abstractions/log.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";
@ -18,6 +17,8 @@ import AutofillField from "../models/autofillField";
import AutofillPageDetails from "../models/autofillPageDetails";
import AutofillScript from "../models/autofillScript";
import { StateService } from "../services/abstractions/state.service";
import { BrowserApi } from "../browser/browserApi";
import {
@ -29,7 +30,7 @@ import {
export default class AutofillService implements AutofillServiceInterface {
constructor(
private cipherService: CipherService,
private userService: UserService,
private stateService: StateService,
private totpService: TotpService,
private eventService: EventService,
private logService: LogService
@ -74,7 +75,7 @@ export default class AutofillService implements AutofillServiceInterface {
throw new Error("Nothing to auto-fill.");
}
const canAccessPremium = await this.userService.canAccessPremium();
const canAccessPremium = await this.stateService.getCanAccessPremium();
let didAutofill = false;
options.pageDetails.forEach((pd: any) => {
// 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";
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 { 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
@ -25,7 +24,7 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
constructor(
private messagingService: MessagingService,
private storageService: StorageService,
private stateService: StateService,
private clipboardWriteCallback: (clipboardValue: string, clearMs: number) => void,
private biometricCallback: () => Promise<boolean>
) {}
@ -367,7 +366,7 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
}
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) {
return this.getDefaultSystemTheme();
} 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));
}
}