mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-23 21:31:29 +01:00
add new storage to replace MasterKey with UserSymKey
This commit is contained in:
parent
7dbc30ee05
commit
702dfb7eaf
@ -26,7 +26,12 @@ import { ServerConfigData } from "../models/data/server-config.data";
|
||||
import { Account, AccountSettingsSettings } from "../models/domain/account";
|
||||
import { EncString } from "../models/domain/enc-string";
|
||||
import { StorageOptions } from "../models/domain/storage-options";
|
||||
import { DeviceKey, SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
import {
|
||||
DeviceKey,
|
||||
MasterKey,
|
||||
SymmetricCryptoKey,
|
||||
UserSymKey,
|
||||
} from "../models/domain/symmetric-crypto-key";
|
||||
|
||||
export abstract class StateService<T extends Account = Account> {
|
||||
accounts$: Observable<{ [userId: string]: T }>;
|
||||
@ -71,6 +76,27 @@ export abstract class StateService<T extends Account = Account> {
|
||||
setCollapsedGroupings: (value: string[], options?: StorageOptions) => Promise<void>;
|
||||
getConvertAccountToKeyConnector: (options?: StorageOptions) => Promise<boolean>;
|
||||
setConvertAccountToKeyConnector: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
|
||||
// new keys
|
||||
getMasterKey: (options?: StorageOptions) => Promise<MasterKey>;
|
||||
setMasterKey: (value: MasterKey, options?: StorageOptions) => Promise<void>;
|
||||
getUserSymKey: (options?: StorageOptions) => Promise<UserSymKey>;
|
||||
setUserSymKey: (value: UserSymKey, options?: StorageOptions) => Promise<void>;
|
||||
getUserSymKeyAuto: (options?: StorageOptions) => Promise<string>;
|
||||
setUserSymKeyAuto: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getUserSymKeyBiometric: (options?: StorageOptions) => Promise<string>;
|
||||
hasUserSymKeyBiometric: (options?: StorageOptions) => Promise<boolean>;
|
||||
setUserSymKeyBiometric: (value: BiometricKey, options?: StorageOptions) => Promise<void>;
|
||||
// end new keys
|
||||
|
||||
// deprecated keys
|
||||
getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<string>;
|
||||
setEncryptedCryptoSymmetricKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||
setDecryptedCryptoSymmetricKey: (
|
||||
value: SymmetricCryptoKey,
|
||||
options?: StorageOptions
|
||||
) => Promise<void>;
|
||||
getCryptoMasterKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||
setCryptoMasterKey: (value: SymmetricCryptoKey, options?: StorageOptions) => Promise<void>;
|
||||
getCryptoMasterKeyAuto: (options?: StorageOptions) => Promise<string>;
|
||||
@ -80,15 +106,12 @@ export abstract class StateService<T extends Account = Account> {
|
||||
getCryptoMasterKeyBiometric: (options?: StorageOptions) => Promise<string>;
|
||||
hasCryptoMasterKeyBiometric: (options?: StorageOptions) => Promise<boolean>;
|
||||
setCryptoMasterKeyBiometric: (value: BiometricKey, options?: StorageOptions) => Promise<void>;
|
||||
// end deprecated keys
|
||||
|
||||
getDecryptedCiphers: (options?: StorageOptions) => Promise<CipherView[]>;
|
||||
setDecryptedCiphers: (value: CipherView[], options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedCollections: (options?: StorageOptions) => Promise<CollectionView[]>;
|
||||
setDecryptedCollections: (value: CollectionView[], options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||
setDecryptedCryptoSymmetricKey: (
|
||||
value: SymmetricCryptoKey,
|
||||
options?: StorageOptions
|
||||
) => Promise<void>;
|
||||
getDecryptedOrganizationKeys: (
|
||||
options?: StorageOptions
|
||||
) => Promise<Map<string, SymmetricCryptoKey>>;
|
||||
@ -205,8 +228,6 @@ export abstract class StateService<T extends Account = Account> {
|
||||
value: { [id: string]: CollectionData },
|
||||
options?: StorageOptions
|
||||
) => Promise<void>;
|
||||
getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<string>;
|
||||
setEncryptedCryptoSymmetricKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
/**
|
||||
* @deprecated Do not call this directly, use FolderService
|
||||
*/
|
||||
|
@ -23,7 +23,7 @@ import { Utils } from "../../misc/utils";
|
||||
import { ServerConfigData } from "../../models/data/server-config.data";
|
||||
|
||||
import { EncString } from "./enc-string";
|
||||
import { DeviceKey, SymmetricCryptoKey } from "./symmetric-crypto-key";
|
||||
import { DeviceKey, MasterKey, SymmetricCryptoKey, UserSymKey } from "./symmetric-crypto-key";
|
||||
|
||||
export class EncryptionPair<TEncrypted, TDecrypted> {
|
||||
encrypted?: TEncrypted;
|
||||
@ -99,6 +99,14 @@ export class AccountData {
|
||||
}
|
||||
|
||||
export class AccountKeys {
|
||||
// new keys
|
||||
masterKey?: MasterKey;
|
||||
userSymKey?: UserSymKey;
|
||||
userSymKeyAuto?: string;
|
||||
userSymKeyBiometric?: string;
|
||||
// end new keys
|
||||
|
||||
//deprecated keys
|
||||
cryptoMasterKey?: SymmetricCryptoKey;
|
||||
cryptoMasterKeyAuto?: string;
|
||||
cryptoMasterKeyB64?: string;
|
||||
@ -107,6 +115,8 @@ export class AccountKeys {
|
||||
string,
|
||||
SymmetricCryptoKey
|
||||
>();
|
||||
// end deprecated keys
|
||||
|
||||
deviceKey?: DeviceKey;
|
||||
organizationKeys?: EncryptionPair<
|
||||
{ [orgId: string]: EncryptedOrganizationKeyData },
|
||||
|
@ -78,3 +78,5 @@ export class SymmetricCryptoKey {
|
||||
|
||||
// Setup all separate key types as opaque types
|
||||
export type DeviceKey = Opaque<SymmetricCryptoKey, "DeviceKey">;
|
||||
export type UserSymKey = Opaque<SymmetricCryptoKey, "UserSymKey">;
|
||||
export type MasterKey = Opaque<SymmetricCryptoKey, "MasterKey">;
|
||||
|
@ -50,7 +50,12 @@ import { EncString } from "../models/domain/enc-string";
|
||||
import { GlobalState } from "../models/domain/global-state";
|
||||
import { State } from "../models/domain/state";
|
||||
import { StorageOptions } from "../models/domain/storage-options";
|
||||
import { DeviceKey, SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
import {
|
||||
DeviceKey,
|
||||
MasterKey,
|
||||
SymmetricCryptoKey,
|
||||
UserSymKey,
|
||||
} from "../models/domain/symmetric-crypto-key";
|
||||
|
||||
const keys = {
|
||||
state: "state",
|
||||
@ -62,6 +67,10 @@ const keys = {
|
||||
};
|
||||
|
||||
const partialKeys = {
|
||||
userAutoKey: "_user_auto",
|
||||
userBiometricKey: "_user_biometric",
|
||||
userSymKey: "_user_sym",
|
||||
|
||||
autoKey: "_masterkey_auto",
|
||||
biometricKey: "_masterkey_biometric",
|
||||
masterKey: "_masterkey",
|
||||
@ -515,6 +524,9 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not save the Master Key. Use the User Symmetric Key instead
|
||||
*/
|
||||
async getCryptoMasterKey(options?: StorageOptions): Promise<SymmetricCryptoKey> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
@ -522,6 +534,9 @@ export class StateService<
|
||||
return account?.keys?.cryptoMasterKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not save the Master Key. Use the User Symmetric Key instead
|
||||
*/
|
||||
async setCryptoMasterKey(value: SymmetricCryptoKey, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
@ -542,6 +557,138 @@ export class StateService<
|
||||
}
|
||||
}
|
||||
|
||||
async getMasterKey(options?: StorageOptions): Promise<MasterKey> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
);
|
||||
return account?.keys?.masterKey;
|
||||
}
|
||||
async setMasterKey(value: MasterKey, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
);
|
||||
account.keys.masterKey = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* User's symmetric key used to encrypt/decrypt data
|
||||
*/
|
||||
async getUserSymKey(options?: StorageOptions): Promise<UserSymKey> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
);
|
||||
return account?.keys?.userSymKey as UserSymKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* User's symmetric key used to encrypt/decrypt data
|
||||
*/
|
||||
async setUserSymKey(value: UserSymKey, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
);
|
||||
account.keys.userSymKey = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
);
|
||||
|
||||
if (options.userId == this.activeAccountSubject.getValue()) {
|
||||
const nextValue = value != null;
|
||||
|
||||
// Avoid emitting if we are already unlocked
|
||||
if (this.activeAccountUnlockedSubject.getValue() != nextValue) {
|
||||
this.activeAccountUnlockedSubject.next(nextValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User's symmetric key when using the "never" option of vault timeout
|
||||
*/
|
||||
async getUserSymKeyAuto(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "auto" }),
|
||||
await this.defaultSecureStorageOptions()
|
||||
);
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}${partialKeys.userAutoKey}`,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* User's symmetric key when using the "never" option of vault timeout
|
||||
*/
|
||||
async setUserSymKeyAuto(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "auto" }),
|
||||
await this.defaultSecureStorageOptions()
|
||||
);
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.saveSecureStorageKey(partialKeys.userAutoKey, value, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* User's encrypted symmetric key when using biometrics
|
||||
*/
|
||||
async getUserSymKeyBiometric(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||
await this.defaultSecureStorageOptions()
|
||||
);
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}${partialKeys.userBiometricKey}`,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* User's encrypted symmetric key when using biometrics
|
||||
*/
|
||||
async hasUserSymKeyBiometric(options?: StorageOptions): Promise<boolean> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||
await this.defaultSecureStorageOptions()
|
||||
);
|
||||
if (options?.userId == null) {
|
||||
return false;
|
||||
}
|
||||
return await this.secureStorageService.has(
|
||||
`${options.userId}${partialKeys.userBiometricKey}`,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* User's encrypted symmetric key when using biometrics
|
||||
*/
|
||||
async setUserSymKeyBiometric(value: BiometricKey, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||
await this.defaultSecureStorageOptions()
|
||||
);
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.saveSecureStorageKey(partialKeys.userBiometricKey, value, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKeyAuto instead
|
||||
*/
|
||||
async getCryptoMasterKeyAuto(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "auto" }),
|
||||
@ -556,6 +703,9 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKeyAuto instead
|
||||
*/
|
||||
async setCryptoMasterKeyAuto(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "auto" }),
|
||||
@ -567,6 +717,9 @@ export class StateService<
|
||||
await this.saveSecureStorageKey(partialKeys.autoKey, value, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated I don't see where this is even used
|
||||
*/
|
||||
async getCryptoMasterKeyB64(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
@ -578,6 +731,9 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated I don't see where this is even used
|
||||
*/
|
||||
async setCryptoMasterKeyB64(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
@ -586,6 +742,9 @@ export class StateService<
|
||||
await this.saveSecureStorageKey(partialKeys.masterKey, value, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKeyBiometric instead
|
||||
*/
|
||||
async getCryptoMasterKeyBiometric(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||
@ -600,6 +759,9 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKeyBiometric instead
|
||||
*/
|
||||
async hasCryptoMasterKeyBiometric(options?: StorageOptions): Promise<boolean> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||
@ -614,6 +776,9 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKeyBiometric instead
|
||||
*/
|
||||
async setCryptoMasterKeyBiometric(value: BiometricKey, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(
|
||||
this.reconcileOptions(options, { keySuffix: "biometric" }),
|
||||
@ -661,6 +826,9 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKey instead
|
||||
*/
|
||||
async getDecryptedCryptoSymmetricKey(options?: StorageOptions): Promise<SymmetricCryptoKey> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||
@ -668,6 +836,9 @@ export class StateService<
|
||||
return account?.keys?.cryptoSymmetricKey?.decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKey instead
|
||||
*/
|
||||
async setDecryptedCryptoSymmetricKey(
|
||||
value: SymmetricCryptoKey,
|
||||
options?: StorageOptions
|
||||
@ -1366,12 +1537,18 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKey instead
|
||||
*/
|
||||
async getEncryptedCryptoSymmetricKey(options?: StorageOptions): Promise<string> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.keys.cryptoSymmetricKey.encrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use UserSymKey instead
|
||||
*/
|
||||
async setEncryptedCryptoSymmetricKey(value: string, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
|
Loading…
Reference in New Issue
Block a user