mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
Auth/PM-5268 - DeviceTrustCryptoService state provider migration (#7882)
* PM-5268 - Add DEVICE_TRUST_DISK to state definitions * PM-5268 - DeviceTrustCryptoService - Get most of state provider refactor done - WIP - commented out stuff for now. * PM-5268 - DeviceTrustCryptoServiceStateProviderMigrator - WIP - got first draft of migrator in place and working on tests. Rollback tests are failing for some reason TBD. * PM-5268 - more WIP on device trust crypto service migrator tests * PM-5268 - DeviceTrustCryptoServiceStateProviderMigrator - Refactor based on call with platform * PM-5268 - DeviceTrustCryptoServiceStateProviderMigrator - tests passing * PM-5268 - Update DeviceTrustCryptoService to convert over to state providers + update all service instantiations / dependencies to ensure state provider is passed in or injected. * PM-5268 - Register new migration * PM-5268 - Temporarily remove device trust crypto service from migrator to ease merge conflicts as there are 6 more migrators before I can apply mine in main. * PM-5268 - Update migration numbers of DeviceTrustCryptoServiceStateProviderMigrator based on latest migrations from main. * PM-5268 - (1) Export new KeyDefinitions from DeviceTrustCryptoService for use in test suite (2) Update DeviceTrustCryptoService test file to use state provider. * PM-5268 - Fix DeviceTrustCryptoServiceStateProviderMigrator tests to use proper versions * PM-5268 - Actually fix all instances of DeviceTrustCryptoServiceStateProviderMigrator test failures * PM-5268 - Clean up state service, account, and login strategy of all migrated references * PM-5268 - Account - finish cleaning up device key * PM-5268 - StateService - clean up last reference to device key * PM-5268 - Remove even more device key refs. *facepalm* * PM-5268 - Finish resolving merge conflicts by incrementing migration version from 22 to 23 * PM-5268 - bump migration versions * PM-5268 - DeviceTrustCryptoService - Implement secure storage functionality for getDeviceKey and setDeviceKey (to achieve feature parity with the ElectronStateService implementation prior to the state provider migration). Tests to follow shortly. * PM-5268 - DeviceTrustCryptoService tests - getDeviceKey now tested with all new secure storage scenarios. SetDeviceKey tests to follow. * PM-5268 - DeviceTrustCryptoService tests - test all setDeviceKey scenarios with state provider & secure storage * PM-5268 - Update DeviceTrustCryptoService deps to actually use secure storage svc on platforms that support it. * PM-5268 - Bump migration version due to merge conflicts. * PM-5268 - Bump migration version * PM-5268 - tweak jsdocs to be single line per PR feedback * PM-5268 - DeviceTrustCryptoSvc - improve debuggability. * PM-5268 - Remove state service as a dependency on the device trust crypto service (woo!) * PM-5268 - Update migration test json to correctly reflect reality. * PM-5268 - DeviceTrustCryptoSvc - getDeviceKey - add throw error for active user id missing. * PM-5268 - Fix tests * PM-5268 - WIP start on adding user id to every method on device trust crypto service. * PM-5268 - Update lock comp dependencies across clients * PM-5268 - Update login via auth request deps across clients to add acct service. * PM-5268 - UserKeyRotationSvc - add acct service to get active acct id for call to rotateDevicesTrust and then update tests. * PM-5268 - WIP on trying to fix device trust crypto svc tests. * PM-5268 - More WIP device trust crypto svc tests passing * PM-5268 - Device Trust crypto service - get all tests passing * PM-5268 - DeviceTrustCryptoService.getDeviceKey - fix secure storage b64 to symmetric crypto key conversion * PM-5268 - Add more tests and update test names * PM-5268 - rename state to indicate it was disk local * PM-5268 - DeviceTrustCryptoService - save symmetric key in JSON format * PM-5268 - Fix lock comp tests by adding acct service dep * PM-5268 - Update set device key tests to pass * PM-5268 - Bump migration versions again * PM-5268 - Fix user key rotation svc tests * PM-5268 - Update web jest config to allow use of common spec in user-key-rotation-svc tests * PM-5268 - Bump migration version * PM-5268 - Per PR feedback, save off user id * PM-5268 - bump migration version * PM-5268 - Per PR feedback, remove unnecessary await. * PM-5268 - Bump migration verson
This commit is contained in:
@@ -10,7 +10,7 @@ import { UsernameGeneratorOptions } from "../../tools/generator/username";
|
||||
import { SendData } from "../../tools/send/models/data/send.data";
|
||||
import { SendView } from "../../tools/send/models/view/send.view";
|
||||
import { UserId } from "../../types/guid";
|
||||
import { DeviceKey, MasterKey } from "../../types/key";
|
||||
import { MasterKey } from "../../types/key";
|
||||
import { CipherData } from "../../vault/models/data/cipher.data";
|
||||
import { LocalData } from "../../vault/models/data/local.data";
|
||||
import { CipherView } from "../../vault/models/view/cipher.view";
|
||||
@@ -161,15 +161,11 @@ export abstract class StateService<T extends Account = Account> {
|
||||
setDecryptedSends: (value: SendView[], options?: StorageOptions) => Promise<void>;
|
||||
getDuckDuckGoSharedKey: (options?: StorageOptions) => Promise<string>;
|
||||
setDuckDuckGoSharedKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getDeviceKey: (options?: StorageOptions) => Promise<DeviceKey | null>;
|
||||
setDeviceKey: (value: DeviceKey | null, options?: StorageOptions) => Promise<void>;
|
||||
getAdminAuthRequest: (options?: StorageOptions) => Promise<AdminAuthRequestStorable | null>;
|
||||
setAdminAuthRequest: (
|
||||
adminAuthRequest: AdminAuthRequestStorable,
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getShouldTrustDevice: (options?: StorageOptions) => Promise<boolean | null>;
|
||||
setShouldTrustDevice: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEmail: (options?: StorageOptions) => Promise<string>;
|
||||
setEmail: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getEmailVerified: (options?: StorageOptions) => Promise<boolean>;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { makeStaticByteArray } from "../../../../spec";
|
||||
import { CsprngArray } from "../../../types/csprng";
|
||||
import { DeviceKey } from "../../../types/key";
|
||||
import { Utils } from "../../misc/utils";
|
||||
|
||||
import { AccountKeys, EncryptionPair } from "./account";
|
||||
@@ -24,23 +22,6 @@ describe("AccountKeys", () => {
|
||||
const json = JSON.stringify(keys);
|
||||
expect(json).toContain('"publicKey":"hello"');
|
||||
});
|
||||
|
||||
// As the accountKeys.toJSON doesn't really serialize the device key
|
||||
// this method just checks the persistence of the deviceKey
|
||||
it("should persist deviceKey", () => {
|
||||
// Arrange
|
||||
const accountKeys = new AccountKeys();
|
||||
const deviceKeyBytesLength = 64;
|
||||
accountKeys.deviceKey = new SymmetricCryptoKey(
|
||||
new Uint8Array(deviceKeyBytesLength).buffer as CsprngArray,
|
||||
) as DeviceKey;
|
||||
|
||||
// Act
|
||||
const serializedKeys = accountKeys.toJSON();
|
||||
|
||||
// Assert
|
||||
expect(serializedKeys.deviceKey).toEqual(accountKeys.deviceKey);
|
||||
});
|
||||
});
|
||||
|
||||
describe("fromJSON", () => {
|
||||
@@ -64,24 +45,5 @@ describe("AccountKeys", () => {
|
||||
} as any);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should deserialize deviceKey", () => {
|
||||
// Arrange
|
||||
const expectedKeyB64 =
|
||||
"ZJNnhx9BbJeb2EAq1hlMjqt6GFsg9G/GzoFf6SbPKsaiMhKGDcbHcwcyEg56Lh8lfilpZz4SRM6UA7oFCg+lSg==";
|
||||
|
||||
const symmetricCryptoKeyFromJsonSpy = jest.spyOn(SymmetricCryptoKey, "fromJSON");
|
||||
|
||||
// Act
|
||||
const accountKeys = AccountKeys.fromJSON({
|
||||
deviceKey: {
|
||||
keyB64: expectedKeyB64,
|
||||
},
|
||||
} as any);
|
||||
|
||||
// Assert
|
||||
expect(symmetricCryptoKeyFromJsonSpy).toHaveBeenCalled();
|
||||
expect(accountKeys.deviceKey.keyB64).toEqual(expectedKeyB64);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -95,7 +95,6 @@ export class AccountData {
|
||||
export class AccountKeys {
|
||||
masterKey?: MasterKey;
|
||||
masterKeyEncryptedUserKey?: string;
|
||||
deviceKey?: ReturnType<SymmetricCryptoKey["toJSON"]>;
|
||||
publicKey?: Uint8Array;
|
||||
|
||||
/** @deprecated July 2023, left for migration purposes*/
|
||||
@@ -125,7 +124,6 @@ export class AccountKeys {
|
||||
}
|
||||
return Object.assign(new AccountKeys(), obj, {
|
||||
masterKey: SymmetricCryptoKey.fromJSON(obj?.masterKey),
|
||||
deviceKey: obj?.deviceKey,
|
||||
cryptoMasterKey: SymmetricCryptoKey.fromJSON(obj?.cryptoMasterKey),
|
||||
cryptoSymmetricKey: EncryptionPair.fromJSON(
|
||||
obj?.cryptoSymmetricKey,
|
||||
@@ -185,7 +183,6 @@ export class AccountSettings {
|
||||
vaultTimeout?: number;
|
||||
vaultTimeoutAction?: string = "lock";
|
||||
approveLoginRequests?: boolean;
|
||||
trustDeviceChoiceForDecryption?: boolean;
|
||||
|
||||
/** @deprecated July 2023, left for migration purposes*/
|
||||
pinProtected?: EncryptionPair<string, EncString> = new EncryptionPair<string, EncString>();
|
||||
|
||||
@@ -14,7 +14,7 @@ import { UsernameGeneratorOptions } from "../../tools/generator/username";
|
||||
import { SendData } from "../../tools/send/models/data/send.data";
|
||||
import { SendView } from "../../tools/send/models/view/send.view";
|
||||
import { UserId } from "../../types/guid";
|
||||
import { DeviceKey, MasterKey } from "../../types/key";
|
||||
import { MasterKey } from "../../types/key";
|
||||
import { CipherData } from "../../vault/models/data/cipher.data";
|
||||
import { LocalData } from "../../vault/models/data/local.data";
|
||||
import { CipherView } from "../../vault/models/view/cipher.view";
|
||||
@@ -650,39 +650,6 @@ export class StateService<
|
||||
: await this.secureStorageService.save(DDG_SHARED_KEY, value, options);
|
||||
}
|
||||
|
||||
async getDeviceKey(options?: StorageOptions): Promise<DeviceKey | null> {
|
||||
options = this.reconcileOptions(options, await this.defaultOnDiskLocalOptions());
|
||||
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const account = await this.getAccount(options);
|
||||
|
||||
const existingDeviceKey = account?.keys?.deviceKey;
|
||||
|
||||
// Must manually instantiate the SymmetricCryptoKey class from the JSON object
|
||||
if (existingDeviceKey != null) {
|
||||
return SymmetricCryptoKey.fromJSON(existingDeviceKey) as DeviceKey;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async setDeviceKey(value: DeviceKey | null, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultOnDiskLocalOptions());
|
||||
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const account = await this.getAccount(options);
|
||||
|
||||
account.keys.deviceKey = value?.toJSON() ?? null;
|
||||
|
||||
await this.saveAccount(account, options);
|
||||
}
|
||||
|
||||
async getAdminAuthRequest(options?: StorageOptions): Promise<AdminAuthRequestStorable | null> {
|
||||
options = this.reconcileOptions(options, await this.defaultOnDiskLocalOptions());
|
||||
|
||||
@@ -714,31 +681,6 @@ export class StateService<
|
||||
await this.saveAccount(account, options);
|
||||
}
|
||||
|
||||
async getShouldTrustDevice(options?: StorageOptions): Promise<boolean | null> {
|
||||
options = this.reconcileOptions(options, await this.defaultOnDiskLocalOptions());
|
||||
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const account = await this.getAccount(options);
|
||||
|
||||
return account?.settings?.trustDeviceChoiceForDecryption ?? null;
|
||||
}
|
||||
|
||||
async setShouldTrustDevice(value: boolean, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultOnDiskLocalOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const account = await this.getAccount(options);
|
||||
|
||||
account.settings.trustDeviceChoiceForDecryption = value;
|
||||
|
||||
await this.saveAccount(account, options);
|
||||
}
|
||||
|
||||
async getEmail(options?: StorageOptions): Promise<string> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions()))
|
||||
@@ -1633,7 +1575,6 @@ export class StateService<
|
||||
protected resetAccount(account: TAccount) {
|
||||
const persistentAccountInformation = {
|
||||
settings: account.settings,
|
||||
keys: { deviceKey: account.keys.deviceKey },
|
||||
adminAuthRequest: account.adminAuthRequest,
|
||||
};
|
||||
return Object.assign(this.createAccount(), persistentAccountInformation);
|
||||
|
||||
@@ -48,6 +48,9 @@ export const TOKEN_DISK_LOCAL = new StateDefinition("tokenDiskLocal", "disk", {
|
||||
web: "disk-local",
|
||||
});
|
||||
export const TOKEN_MEMORY = new StateDefinition("token", "memory");
|
||||
export const DEVICE_TRUST_DISK_LOCAL = new StateDefinition("deviceTrust", "disk", {
|
||||
web: "disk-local",
|
||||
});
|
||||
export const USER_DECRYPTION_OPTIONS_DISK = new StateDefinition("userDecryptionOptions", "disk");
|
||||
|
||||
// Autofill
|
||||
|
||||
Reference in New Issue
Block a user