mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
Add state for everHadUserKey (#7208)
* Migrate ever had user key * Add DI for state providers * Add state for everHadUserKey * Use ever had user key migrator Co-authored-by: SmithThe4th <gsmithwalter@gmail.com> Co-authored-by: Carlos Gonçalves <LRNcardozoWDF@users.noreply.github.com> Co-authored-by: Jason Ng <Jcory.ng@gmail.com> * Fix test from merge * Prefer stored observables to getters getters create a new observable every time they're called, whereas one set in the constructor is created only once. * Fix another merge issue * Fix cli background build --------- Co-authored-by: SmithThe4th <gsmithwalter@gmail.com> Co-authored-by: Carlos Gonçalves <LRNcardozoWDF@users.noreply.github.com> Co-authored-by: Jason Ng <Jcory.ng@gmail.com>
This commit is contained in:
@@ -311,7 +311,6 @@ export default class MainBackground {
|
||||
this.memoryStorageService as BackgroundMemoryStorageService,
|
||||
this.storageService as BrowserLocalStorageService,
|
||||
);
|
||||
|
||||
this.encryptService = flagEnabled("multithreadDecryption")
|
||||
? new MultithreadEncryptServiceImplementation(
|
||||
this.cryptoFunctionService,
|
||||
@@ -374,13 +373,14 @@ export default class MainBackground {
|
||||
window,
|
||||
);
|
||||
this.i18nService = new BrowserI18nService(BrowserApi.getUILanguage(), this.stateService);
|
||||
|
||||
this.cryptoService = new BrowserCryptoService(
|
||||
this.cryptoFunctionService,
|
||||
this.encryptService,
|
||||
this.platformUtilsService,
|
||||
this.logService,
|
||||
this.stateService,
|
||||
this.accountService,
|
||||
this.stateProvider,
|
||||
);
|
||||
this.tokenService = new TokenService(this.stateService);
|
||||
this.appIdService = new AppIdService(this.storageService);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { CryptoService as AbstractCryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
|
||||
import {
|
||||
AccountServiceInitOptions,
|
||||
accountServiceFactory,
|
||||
} from "../../../auth/background/service-factories/account-service.factory";
|
||||
import {
|
||||
StateServiceInitOptions,
|
||||
stateServiceFactory,
|
||||
@@ -20,6 +24,7 @@ import {
|
||||
PlatformUtilsServiceInitOptions,
|
||||
platformUtilsServiceFactory,
|
||||
} from "./platform-utils-service.factory";
|
||||
import { StateProviderInitOptions, stateProviderFactory } from "./state-provider.factory";
|
||||
|
||||
type CryptoServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
@@ -28,7 +33,9 @@ export type CryptoServiceInitOptions = CryptoServiceFactoryOptions &
|
||||
EncryptServiceInitOptions &
|
||||
PlatformUtilsServiceInitOptions &
|
||||
LogServiceInitOptions &
|
||||
StateServiceInitOptions;
|
||||
StateServiceInitOptions &
|
||||
AccountServiceInitOptions &
|
||||
StateProviderInitOptions;
|
||||
|
||||
export function cryptoServiceFactory(
|
||||
cache: { cryptoService?: AbstractCryptoService } & CachedServices,
|
||||
@@ -45,6 +52,8 @@ export function cryptoServiceFactory(
|
||||
await platformUtilsServiceFactory(cache, opts),
|
||||
await logServiceFactory(cache, opts),
|
||||
await stateServiceFactory(cache, opts),
|
||||
await accountServiceFactory(cache, opts),
|
||||
await stateProviderFactory(cache, opts),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ import {
|
||||
UserKey,
|
||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
export class BrowserCryptoService extends CryptoService {
|
||||
override async hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: string): Promise<boolean> {
|
||||
override async hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: UserId): Promise<boolean> {
|
||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||
return await this.stateService.getBiometricUnlock({ userId: userId });
|
||||
}
|
||||
@@ -20,7 +21,7 @@ export class BrowserCryptoService extends CryptoService {
|
||||
*/
|
||||
protected override async getKeyFromStorage(
|
||||
keySuffix: KeySuffixOptions,
|
||||
userId?: string,
|
||||
userId?: UserId,
|
||||
): Promise<UserKey> {
|
||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||
await this.platformUtilService.authenticateBiometric();
|
||||
|
||||
@@ -268,6 +268,8 @@ export class Main {
|
||||
this.platformUtilsService,
|
||||
this.logService,
|
||||
this.stateService,
|
||||
this.accountService,
|
||||
this.stateProvider,
|
||||
);
|
||||
|
||||
this.appIdService = new AppIdService(this.storageService);
|
||||
|
||||
@@ -37,6 +37,7 @@ import { StateFactory } from "@bitwarden/common/platform/factories/state-factory
|
||||
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
||||
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
||||
import { SystemService } from "@bitwarden/common/platform/services/system.service";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
@@ -180,6 +181,8 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
||||
PlatformUtilsServiceAbstraction,
|
||||
LogService,
|
||||
StateServiceAbstraction,
|
||||
AccountServiceAbstraction,
|
||||
StateProvider,
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mock, mockReset } from "jest-mock-extended";
|
||||
import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider";
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
@@ -9,6 +10,12 @@ import {
|
||||
UserKey,
|
||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import {
|
||||
FakeAccountService,
|
||||
mockAccountServiceWith,
|
||||
} from "../../../../../libs/common/spec/fake-account-service";
|
||||
|
||||
import { ElectronCryptoService } from "./electron-crypto.service";
|
||||
import { ElectronStateService } from "./electron-state.service.abstraction";
|
||||
@@ -21,15 +28,14 @@ describe("electronCryptoService", () => {
|
||||
const platformUtilService = mock<PlatformUtilsService>();
|
||||
const logService = mock<LogService>();
|
||||
const stateService = mock<ElectronStateService>();
|
||||
let accountService: FakeAccountService;
|
||||
let stateProvider: FakeStateProvider;
|
||||
|
||||
const mockUserId = "mock user id";
|
||||
const mockUserId = "mock user id" as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
mockReset(cryptoFunctionService);
|
||||
mockReset(encryptService);
|
||||
mockReset(platformUtilService);
|
||||
mockReset(logService);
|
||||
mockReset(stateService);
|
||||
accountService = mockAccountServiceWith("userId" as UserId);
|
||||
stateProvider = new FakeStateProvider(accountService);
|
||||
|
||||
electronCryptoService = new ElectronCryptoService(
|
||||
cryptoFunctionService,
|
||||
@@ -37,9 +43,15 @@ describe("electronCryptoService", () => {
|
||||
platformUtilService,
|
||||
logService,
|
||||
stateService,
|
||||
accountService,
|
||||
stateProvider,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it("instantiates", () => {
|
||||
expect(electronCryptoService).not.toBeFalsy();
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@@ -11,7 +12,9 @@ import {
|
||||
UserKey,
|
||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { CsprngString } from "@bitwarden/common/types/csprng";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { ElectronStateService } from "./electron-state.service.abstraction";
|
||||
|
||||
@@ -22,11 +25,21 @@ export class ElectronCryptoService extends CryptoService {
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
logService: LogService,
|
||||
protected override stateService: ElectronStateService,
|
||||
accountService: AccountService,
|
||||
stateProvider: StateProvider,
|
||||
) {
|
||||
super(cryptoFunctionService, encryptService, platformUtilsService, logService, stateService);
|
||||
super(
|
||||
cryptoFunctionService,
|
||||
encryptService,
|
||||
platformUtilsService,
|
||||
logService,
|
||||
stateService,
|
||||
accountService,
|
||||
stateProvider,
|
||||
);
|
||||
}
|
||||
|
||||
override async hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: string): Promise<boolean> {
|
||||
override async hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: UserId): Promise<boolean> {
|
||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||
// TODO: Remove after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3474)
|
||||
const oldKey = await this.stateService.hasCryptoMasterKeyBiometric({ userId: userId });
|
||||
@@ -35,7 +48,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
return super.hasUserKeyStored(keySuffix, userId);
|
||||
}
|
||||
|
||||
override async clearStoredUserKey(keySuffix: KeySuffixOptions, userId?: string): Promise<void> {
|
||||
override async clearStoredUserKey(keySuffix: KeySuffixOptions, userId?: UserId): Promise<void> {
|
||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||
this.stateService.setUserKeyBiometric(null, { userId: userId });
|
||||
this.clearDeprecatedKeys(KeySuffixOptions.Biometric, userId);
|
||||
@@ -44,7 +57,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
super.clearStoredUserKey(keySuffix, userId);
|
||||
}
|
||||
|
||||
protected override async storeAdditionalKeys(key: UserKey, userId?: string) {
|
||||
protected override async storeAdditionalKeys(key: UserKey, userId?: UserId) {
|
||||
await super.storeAdditionalKeys(key, userId);
|
||||
|
||||
const storeBiometricKey = await this.shouldStoreKey(KeySuffixOptions.Biometric, userId);
|
||||
@@ -59,7 +72,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
|
||||
protected override async getKeyFromStorage(
|
||||
keySuffix: KeySuffixOptions,
|
||||
userId?: string,
|
||||
userId?: UserId,
|
||||
): Promise<UserKey> {
|
||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||
await this.migrateBiometricKeyIfNeeded(userId);
|
||||
@@ -69,7 +82,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
return await super.getKeyFromStorage(keySuffix, userId);
|
||||
}
|
||||
|
||||
protected async storeBiometricKey(key: UserKey, userId?: string): Promise<void> {
|
||||
protected async storeBiometricKey(key: UserKey, userId?: UserId): Promise<void> {
|
||||
let clientEncKeyHalf: CsprngString = null;
|
||||
if (await this.stateService.getBiometricRequirePasswordOnStart({ userId })) {
|
||||
clientEncKeyHalf = await this.getBiometricEncryptionClientKeyHalf(userId);
|
||||
@@ -80,7 +93,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
);
|
||||
}
|
||||
|
||||
protected async shouldStoreKey(keySuffix: KeySuffixOptions, userId?: string): Promise<boolean> {
|
||||
protected async shouldStoreKey(keySuffix: KeySuffixOptions, userId?: UserId): Promise<boolean> {
|
||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||
const biometricUnlock = await this.stateService.getBiometricUnlock({ userId: userId });
|
||||
return biometricUnlock && this.platformUtilService.supportsSecureStorage();
|
||||
@@ -88,12 +101,12 @@ export class ElectronCryptoService extends CryptoService {
|
||||
return await super.shouldStoreKey(keySuffix, userId);
|
||||
}
|
||||
|
||||
protected override async clearAllStoredUserKeys(userId?: string): Promise<void> {
|
||||
protected override async clearAllStoredUserKeys(userId?: UserId): Promise<void> {
|
||||
await this.stateService.setUserKeyBiometric(null, { userId: userId });
|
||||
super.clearAllStoredUserKeys(userId);
|
||||
}
|
||||
|
||||
private async getBiometricEncryptionClientKeyHalf(userId?: string): Promise<CsprngString | null> {
|
||||
private async getBiometricEncryptionClientKeyHalf(userId?: UserId): Promise<CsprngString | null> {
|
||||
try {
|
||||
let biometricKey = await this.stateService
|
||||
.getBiometricEncryptionClientKeyHalf({ userId })
|
||||
@@ -118,7 +131,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
// These methods support migrating the old keys to the new ones.
|
||||
// TODO: Remove after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3475)
|
||||
|
||||
override async clearDeprecatedKeys(keySuffix: KeySuffixOptions, userId?: string) {
|
||||
override async clearDeprecatedKeys(keySuffix: KeySuffixOptions, userId?: UserId) {
|
||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||
await this.stateService.setCryptoMasterKeyBiometric(null, { userId: userId });
|
||||
}
|
||||
@@ -126,7 +139,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
super.clearDeprecatedKeys(keySuffix, userId);
|
||||
}
|
||||
|
||||
private async migrateBiometricKeyIfNeeded(userId?: string) {
|
||||
private async migrateBiometricKeyIfNeeded(userId?: UserId) {
|
||||
if (await this.stateService.hasCryptoMasterKeyBiometric({ userId })) {
|
||||
const oldBiometricKey = await this.stateService.getCryptoMasterKeyBiometric({ userId });
|
||||
// decrypt
|
||||
|
||||
Reference in New Issue
Block a user