mirror of
https://github.com/bitwarden/jslib
synced 2026-01-03 00:53:13 +00:00
laptop issue
This commit is contained in:
@@ -155,6 +155,7 @@ export class LockComponent implements OnInit {
|
||||
}
|
||||
|
||||
const success = (await this.cryptoService.getKey(KeySuffixOptions.Biometric)) != null;
|
||||
console.debug('unlockBiometric', success)
|
||||
|
||||
if (success) {
|
||||
await this.doContinue();
|
||||
|
||||
@@ -65,12 +65,12 @@ export abstract class StateService {
|
||||
setConvertAccountToKeyConnector: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getCryptoMasterKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||
setCryptoMasterKey: (value: SymmetricCryptoKey, options?: StorageOptions) => Promise<void>;
|
||||
getCryptoMasterKeyAuto: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||
setCryptoMasterKeyAuto: (value: SymmetricCryptoKey, options?: StorageOptions) => Promise<void>;
|
||||
getCryptoMasterKeyB64: (options: StorageOptions) => Promise<string>;
|
||||
setCryptoMasterKeyB64: (value: string, options: StorageOptions) => Promise<void>;
|
||||
getCryptoMasterKeyBiometric: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||
setCryptoMasterKeyBiometric: (value: SymmetricCryptoKey, options?: StorageOptions) => Promise<void>;
|
||||
getCryptoMasterKeyAuto: (options?: StorageOptions) => Promise<string>;
|
||||
setCryptoMasterKeyAuto: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getCryptoMasterKeyB64: (options?: StorageOptions) => Promise<string>;
|
||||
setCryptoMasterKeyB64: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getCryptoMasterKeyBiometric: (options?: StorageOptions) => Promise<string>;
|
||||
setCryptoMasterKeyBiometric: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getDecodedToken: (options?: StorageOptions) => Promise<any>;
|
||||
setDecodedToken: (value: any, options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedCiphers: (options?: StorageOptions) => Promise<CipherView[]>;
|
||||
|
||||
@@ -49,9 +49,9 @@ export class AccountData {
|
||||
|
||||
export class AccountKeys {
|
||||
cryptoMasterKey: SymmetricCryptoKey;
|
||||
cryptoMasterKeyAuto: SymmetricCryptoKey;
|
||||
cryptoMasterKeyAuto: string;
|
||||
cryptoMasterKeyB64: string;
|
||||
cryptoMasterKeyBiometric: SymmetricCryptoKey;
|
||||
cryptoMasterKeyBiometric: string;
|
||||
cryptoSymmetricKey: EncryptionPair<string, SymmetricCryptoKey> = new EncryptionPair<string, SymmetricCryptoKey>();
|
||||
organizationKeys: EncryptionPair<any, Map<string, SymmetricCryptoKey>> = new EncryptionPair<any, Map<string, SymmetricCryptoKey>>();
|
||||
providerKeys: EncryptionPair<any, Map<string, SymmetricCryptoKey>> = new EncryptionPair<any, Map<string, SymmetricCryptoKey>>();
|
||||
@@ -89,7 +89,6 @@ export class AccountSettings {
|
||||
autoConfirmFingerPrints: boolean;
|
||||
autoFillOnPageLoadDefault: boolean;
|
||||
biometricLocked: boolean;
|
||||
biometricText: string;
|
||||
biometricUnlock: boolean;
|
||||
clearClipboard: number;
|
||||
defaultUriMatch: UriMatchType;
|
||||
@@ -105,7 +104,6 @@ export class AccountSettings {
|
||||
enableAlwaysOnTop: boolean;
|
||||
enableAutoFillOnPageLoad: boolean;
|
||||
enableBiometric: boolean;
|
||||
enableBiometrics: boolean;
|
||||
enableBrowserIntegration: boolean;
|
||||
enableBrowserIntegrationFingerprint: boolean;
|
||||
enableCloseToTray: boolean;
|
||||
@@ -119,8 +117,6 @@ export class AccountSettings {
|
||||
locale: string;
|
||||
minimizeOnCopyToClipboard: boolean;
|
||||
neverDomains: { [id: string]: any };
|
||||
noAutoPromptBiometrics: boolean;
|
||||
noAutoPromptBiometricsText: string;
|
||||
openAtLogin: boolean;
|
||||
passwordGenerationOptions: any;
|
||||
pinProtected: EncryptionPair<string, EncString> = new EncryptionPair<string, EncString>();
|
||||
|
||||
@@ -16,4 +16,8 @@ export class GlobalState {
|
||||
vaultTimeoutAction: string;
|
||||
loginRedirect: any;
|
||||
mainWindowSize: number;
|
||||
enableBiometrics: boolean;
|
||||
biometricText: string;
|
||||
noAutoPromptBiometrics: boolean;
|
||||
noAutoPromptBiometricsText: string;
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ export type StorageOptions = {
|
||||
useSecureStorage?: boolean;
|
||||
userId?: string;
|
||||
htmlStorageLocation?: HtmlStorageLocation;
|
||||
keySuffix?: string,
|
||||
};
|
||||
|
||||
@@ -87,10 +87,12 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
const inMemoryKey = await this.stateService.getCryptoMasterKey({ userId: userId });
|
||||
|
||||
if (inMemoryKey != null) {
|
||||
console.debug('found another key. not clearing correctly on lock probably');
|
||||
return inMemoryKey;
|
||||
}
|
||||
|
||||
keySuffix ||= KeySuffixOptions.Auto;
|
||||
console.debug('getKey', { keySuffix , key: await this.getKeyFromStorage(keySuffix, userId)});
|
||||
const symmetricKey = await this.getKeyFromStorage(keySuffix, userId);
|
||||
|
||||
if (symmetricKey != null) {
|
||||
@@ -103,7 +105,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
async getKeyFromStorage(keySuffix: KeySuffixOptions, userId?: string): Promise<SymmetricCryptoKey> {
|
||||
const key = await this.retrieveKeyFromStorage(keySuffix, userId);
|
||||
if (key != null) {
|
||||
const symmetricKey = new SymmetricCryptoKey(Utils.fromB64ToArray(key.keyB64).buffer);
|
||||
const symmetricKey = new SymmetricCryptoKey(Utils.fromB64ToArray(key).buffer);
|
||||
|
||||
if (!await this.validateKey(symmetricKey)) {
|
||||
this.logService.warning('Wrong key, throwing away stored key');
|
||||
@@ -345,8 +347,8 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
await this.stateService.setCryptoMasterKeyBiometric(null);
|
||||
}
|
||||
|
||||
async clearKeyHash(): Promise<any> {
|
||||
return await this.stateService.setKeyHash(null);
|
||||
async clearKeyHash(userId?: string): Promise<any> {
|
||||
return await this.stateService.setKeyHash(null, { userId: userId });
|
||||
}
|
||||
|
||||
async clearEncKey(memoryOnly?: boolean, userId?: string): Promise<void> {
|
||||
@@ -374,25 +376,25 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
}
|
||||
}
|
||||
|
||||
async clearProviderKeys(memoryOnly?: boolean): Promise<void> {
|
||||
await this.stateService.setDecryptedProviderKeys(null);
|
||||
async clearProviderKeys(memoryOnly?: boolean, userId?: string): Promise<void> {
|
||||
await this.stateService.setDecryptedProviderKeys(null, { userId: userId });
|
||||
if (!memoryOnly) {
|
||||
await this.stateService.setEncryptedProviderKeys(null);
|
||||
await this.stateService.setEncryptedProviderKeys(null, { userId: userId });
|
||||
}
|
||||
}
|
||||
|
||||
async clearPinProtectedKey(): Promise<any> {
|
||||
return await this.stateService.setDecryptedPinProtected(null);
|
||||
async clearPinProtectedKey(userId?: string): Promise<any> {
|
||||
return await this.stateService.setDecryptedPinProtected(null, { userId: userId });
|
||||
}
|
||||
|
||||
async clearKeys(): Promise<any> {
|
||||
await this.clearKey();
|
||||
await this.clearKeyHash();
|
||||
await this.clearOrgKeys();
|
||||
await this.clearProviderKeys();
|
||||
await this.clearEncKey();
|
||||
await this.clearKeyPair();
|
||||
await this.clearPinProtectedKey();
|
||||
async clearKeys(userId?: string): Promise<any> {
|
||||
await this.clearKey(true, userId);
|
||||
await this.clearKeyHash(userId);
|
||||
await this.clearOrgKeys(false, userId);
|
||||
await this.clearProviderKeys(false, userId);
|
||||
await this.clearEncKey(false, userId);
|
||||
await this.clearKeyPair(false, userId);
|
||||
await this.clearPinProtectedKey(userId);
|
||||
}
|
||||
|
||||
async toggleKey(): Promise<any> {
|
||||
@@ -694,7 +696,13 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
protected async storeKey(key: SymmetricCryptoKey, userId?: string) {
|
||||
if (await this.shouldStoreKey(KeySuffixOptions.Auto, userId) || await this.shouldStoreKey(KeySuffixOptions.Biometric, userId)) {
|
||||
await this.stateService.setCryptoMasterKeyB64(key.keyB64, { userId: userId });
|
||||
} else {
|
||||
await this.stateService.setCryptoMasterKeyB64(null, { userId: userId });
|
||||
}
|
||||
}
|
||||
|
||||
protected async shouldStoreKey(keySuffix: KeySuffixOptions, userId?: string) {
|
||||
let shouldStoreKey = false;
|
||||
@@ -862,25 +870,8 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
return [new SymmetricCryptoKey(encKey), encKeyEnc];
|
||||
}
|
||||
|
||||
private async getSuffix(userId?: string): Promise<KeySuffixOptions> {
|
||||
return await this.shouldStoreKey(KeySuffixOptions.Auto, userId) ?
|
||||
KeySuffixOptions.Auto :
|
||||
await this.shouldStoreKey(KeySuffixOptions.Biometric, userId) ?
|
||||
KeySuffixOptions.Biometric :
|
||||
null;
|
||||
}
|
||||
|
||||
private async clearSecretKeyStore(userId?: string): Promise<void> {
|
||||
await this.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
|
||||
await this.stateService.setCryptoMasterKeyBiometric(null, { userId: userId });
|
||||
}
|
||||
|
||||
private async storeKey(key: SymmetricCryptoKey, userId?: string) {
|
||||
const shouldStoreAuto = await this.shouldStoreKey(KeySuffixOptions.Auto, userId);
|
||||
await this.stateService.setCryptoMasterKeyAuto(shouldStoreAuto ? key : null, { userId: userId });
|
||||
|
||||
const shouldStoreBiometric = await this.shouldStoreKey(KeySuffixOptions.Biometric, userId);
|
||||
await this.stateService.setCryptoMasterKeyBiometric(shouldStoreBiometric ? key : null, { userId: userId });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,16 @@ export class StateService implements StateServiceAbstraction {
|
||||
if (await this.getActiveUserIdFromStorage() != null) {
|
||||
const diskState = await this.storageService.get<State>('state', await this.defaultOnDiskOptions());
|
||||
this.state = diskState;
|
||||
await this.saveStateToStorage(diskState, await this.defaultOnDiskMemoryOptions());
|
||||
|
||||
// if (this.state.accounts != null && Object.keys(this.state.accounts).length > 0) {
|
||||
// // Long term storage mechanisms may return undefined for nested account objects that we always want initilized
|
||||
// // Reconstruct them here to ensure things like serverUrl are always accessible for all accounts
|
||||
// for (const userId in this.state.accounts) {
|
||||
// this.state.accounts[userId] = new Account(this.state.accounts[userId]);
|
||||
// }
|
||||
// }
|
||||
|
||||
await this.saveStateToStorage(this.state, await this.defaultOnDiskMemoryOptions());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,19 +186,19 @@ export class StateService implements StateServiceAbstraction {
|
||||
}
|
||||
|
||||
async setBiometricLocked(value: boolean, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
const account = await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions));
|
||||
account.settings.biometricLocked = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions));
|
||||
}
|
||||
|
||||
async getBiometricText(options?: StorageOptions): Promise<string> {
|
||||
return (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))?.settings?.biometricText;
|
||||
return (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))?.biometricText;
|
||||
}
|
||||
|
||||
async setBiometricText(value: string, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
account.settings.biometricText = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
const globals = await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
globals.biometricText = value;
|
||||
await this.saveGlobals(globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
}
|
||||
|
||||
async getBiometricUnlock(options?: StorageOptions): Promise<boolean> {
|
||||
@@ -263,44 +272,47 @@ export class StateService implements StateServiceAbstraction {
|
||||
|
||||
async setCryptoMasterKey(value: SymmetricCryptoKey, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions));
|
||||
console.debug('setting crypto master key', {
|
||||
email: account.profile.email,
|
||||
requestedUserId: options?.userId,
|
||||
requestedUserEmail: await this.getEmail({ userId: options?.userId }),
|
||||
account: account,
|
||||
vaule: value,
|
||||
})
|
||||
account.keys.cryptoMasterKey = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions));
|
||||
}
|
||||
|
||||
async getCryptoMasterKeyAuto(options?: StorageOptions): Promise<SymmetricCryptoKey> {
|
||||
async getCryptoMasterKeyAuto(options?: StorageOptions): Promise<string> {
|
||||
return (await this.getAccount(this.reconcileOptions(options, await this.defaultSecureStorageOptions())))?.keys?.cryptoMasterKeyAuto;
|
||||
}
|
||||
|
||||
async setCryptoMasterKeyAuto(value: SymmetricCryptoKey, options?: StorageOptions): Promise<void> {
|
||||
async setCryptoMasterKeyAuto(value: string, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultSecureStorageOptions()));
|
||||
account.keys.cryptoMasterKeyAuto = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultSecureStorageOptions()));
|
||||
}
|
||||
|
||||
async getCryptoMasterKeyB64(options: StorageOptions): Promise<string> {
|
||||
async getCryptoMasterKeyB64(options?: StorageOptions): Promise<string> {
|
||||
const value = (await this.getAccount(this.reconcileOptions(options, await this.defaultSecureStorageOptions())))?.keys?.cryptoMasterKeyB64;
|
||||
return value;
|
||||
}
|
||||
|
||||
async setCryptoMasterKeyB64(value: string, options: StorageOptions): Promise<void> {
|
||||
try {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultSecureStorageOptions()));
|
||||
if (account != null) {
|
||||
account.keys.cryptoMasterKeyB64 = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultSecureStorageOptions()));
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
async setCryptoMasterKeyB64(value: string, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultSecureStorageOptions()));
|
||||
account.keys.cryptoMasterKeyB64 = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultSecureStorageOptions()));
|
||||
}
|
||||
|
||||
async getCryptoMasterKeyBiometric(options?: StorageOptions): Promise<SymmetricCryptoKey> {
|
||||
async getCryptoMasterKeyBiometric(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, { keySuffix: 'biometric' })
|
||||
return (await this.getAccount(this.reconcileOptions(options, await this.defaultSecureStorageOptions())))?.keys?.cryptoMasterKeyBiometric;
|
||||
}
|
||||
|
||||
async setCryptoMasterKeyBiometric(value: SymmetricCryptoKey, options?: StorageOptions): Promise<void> {
|
||||
async setCryptoMasterKeyBiometric(value: string, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultSecureStorageOptions()));
|
||||
account.keys.cryptoMasterKeyBiometric = value;
|
||||
console.debug('saving biometric key', value);
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultSecureStorageOptions()));
|
||||
}
|
||||
|
||||
@@ -577,12 +589,12 @@ export class StateService implements StateServiceAbstraction {
|
||||
}
|
||||
|
||||
async getEnableBiometric(options?: StorageOptions): Promise<boolean> {
|
||||
return (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))?.settings?.enableBiometrics ?? false;
|
||||
return (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))?.enableBiometrics ?? false;
|
||||
}
|
||||
async setEnableBiometric(value: boolean, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
account.settings.enableBiometrics = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
const globals = await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
globals.enableBiometrics = value;
|
||||
await this.saveGlobals(globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
}
|
||||
|
||||
async getEnableBrowserIntegration(options?: StorageOptions): Promise<boolean> {
|
||||
@@ -950,21 +962,21 @@ export class StateService implements StateServiceAbstraction {
|
||||
}
|
||||
|
||||
async getNoAutoPromptBiometrics(options?: StorageOptions): Promise<boolean> {
|
||||
return (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))?.settings?.noAutoPromptBiometrics ?? false;
|
||||
return (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))?.noAutoPromptBiometrics ?? false;
|
||||
}
|
||||
async setNoAutoPromptBiometrics(value: boolean, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
account.settings.noAutoPromptBiometrics = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
const globals = await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
globals.noAutoPromptBiometrics = value;
|
||||
await this.saveGlobals(globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
}
|
||||
|
||||
async getNoAutoPromptBiometricsText(options?: StorageOptions): Promise<string> {
|
||||
return (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))?.settings?.noAutoPromptBiometricsText;
|
||||
return (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))?.noAutoPromptBiometricsText;
|
||||
}
|
||||
async setNoAutoPromptBiometricsText(value: string, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
account.settings.noAutoPromptBiometricsText = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
const globals = await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
globals.noAutoPromptBiometricsText = value;
|
||||
await this.saveGlobals(globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()));
|
||||
}
|
||||
|
||||
async getOpenAtLogin(options?: StorageOptions): Promise<boolean> {
|
||||
@@ -1339,30 +1351,9 @@ export class StateService implements StateServiceAbstraction {
|
||||
|
||||
private async pushAccounts(): Promise<void> {
|
||||
if (this.state?.accounts == null || Object.keys(this.state.accounts).length < 1) {
|
||||
this.accounts.next(null);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const i in this.state.accounts) {
|
||||
if (this.state.accounts[i]?.profile?.userId == null) {
|
||||
continue;
|
||||
}
|
||||
if (this.state.accounts[i].profile.userId === this.state.activeUserId) {
|
||||
this.state.accounts[i].profile.authenticationStatus = AuthenticationStatus.Active;
|
||||
} else {
|
||||
const vaultTimeout = await this.getVaultTimeout({
|
||||
storageLocation: StorageLocation.Disk,
|
||||
userId: this.state.accounts[i].profile.userId,
|
||||
});
|
||||
const lastActive = await this.getLastActive({
|
||||
storageLocation: StorageLocation.Disk,
|
||||
userId: this.state.accounts[i].profile.userId,
|
||||
});
|
||||
const diffSeconds = ((new Date()).getTime() - lastActive) / 1000;
|
||||
this.state.accounts[i].profile.authenticationStatus = diffSeconds < (vaultTimeout * 60) ?
|
||||
AuthenticationStatus.Unlocked :
|
||||
AuthenticationStatus.Locked;
|
||||
}
|
||||
}
|
||||
this.accounts.next(this.state.accounts);
|
||||
}
|
||||
|
||||
@@ -1374,6 +1365,7 @@ export class StateService implements StateServiceAbstraction {
|
||||
requestedOptions.storageLocation = requestedOptions?.storageLocation ?? defaultOptions.storageLocation;
|
||||
requestedOptions.useSecureStorage = requestedOptions?.useSecureStorage ?? defaultOptions.useSecureStorage;
|
||||
requestedOptions.htmlStorageLocation = requestedOptions?.htmlStorageLocation ?? defaultOptions.htmlStorageLocation;
|
||||
requestedOptions.keySuffix = requestedOptions?.keySuffix ?? defaultOptions.keySuffix;
|
||||
return requestedOptions;
|
||||
}
|
||||
|
||||
@@ -1427,12 +1419,7 @@ export class StateService implements StateServiceAbstraction {
|
||||
return;
|
||||
}
|
||||
|
||||
state.accounts[userId] = new Account({
|
||||
profile: state.accounts[userId].profile,
|
||||
settings: state.accounts[userId].settings,
|
||||
data: state.accounts[userId].data,
|
||||
});
|
||||
|
||||
delete state.accounts[userId];
|
||||
await this.saveStateToStorage(state, await this.defaultOnDiskLocalOptions());
|
||||
}
|
||||
|
||||
@@ -1442,12 +1429,7 @@ export class StateService implements StateServiceAbstraction {
|
||||
return;
|
||||
}
|
||||
|
||||
state.accounts[userId] = new Account({
|
||||
profile: state.accounts[userId].profile,
|
||||
settings: state.accounts[userId].settings,
|
||||
data: state.accounts[userId].data,
|
||||
});
|
||||
|
||||
delete state.accounts[userId];
|
||||
await this.saveStateToStorage(state, await this.defaultOnDiskOptions());
|
||||
}
|
||||
|
||||
@@ -1456,15 +1438,13 @@ export class StateService implements StateServiceAbstraction {
|
||||
if (state?.accounts[userId] == null) {
|
||||
return;
|
||||
}
|
||||
state.accounts[userId] = null;
|
||||
|
||||
delete state.accounts[userId];
|
||||
await this.secureStorageService.save('state', state);
|
||||
}
|
||||
|
||||
private removeAccountFromMemory(userId: string = this.state.activeUserId): void {
|
||||
if (this.state?.accounts[userId] == null) {
|
||||
return;
|
||||
}
|
||||
delete this.state.accounts[userId ?? this.state.activeUserId];
|
||||
delete this.state.accounts[userId];
|
||||
}
|
||||
|
||||
private async saveStateToStorage(state: State, options: StorageOptions): Promise<void> {
|
||||
|
||||
@@ -47,7 +47,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
||||
const neverLock = await this.cryptoService.hasKeyStored(KeySuffixOptions.Auto, userId) &&
|
||||
!(await this.stateService.getEverBeenUnlocked({ userId: userId }));
|
||||
if (neverLock) {
|
||||
// TODO: This also sets the key so when we check memory in the next line it finds a key.
|
||||
// TODO: This also _sets_ the key so when we check memory in the next line it finds a key.
|
||||
// We should refactor here.
|
||||
await this.cryptoService.getKey(KeySuffixOptions.Auto, userId);
|
||||
}
|
||||
@@ -86,17 +86,20 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
||||
this.searchService.clearIndex();
|
||||
}
|
||||
|
||||
await this.folderService.clearCache(userId);
|
||||
await this.cipherService.clearCache(userId);
|
||||
await this.collectionService.clearCache(userId);
|
||||
await this.stateService.setEverBeenUnlocked(true, { userId: userId });
|
||||
await this.stateService.setBiometricLocked(true, { userId: userId });
|
||||
|
||||
await this.cryptoService.clearKey(false, userId);
|
||||
await this.cryptoService.clearOrgKeys(true, userId);
|
||||
await this.cryptoService.clearKeyPair(true, userId);
|
||||
await this.cryptoService.clearEncKey(true, userId);
|
||||
await this.stateService.setBiometricLocked(true, { userId: userId });
|
||||
|
||||
await this.folderService.clearCache(userId);
|
||||
await this.cipherService.clearCache(userId);
|
||||
await this.collectionService.clearCache(userId);
|
||||
|
||||
this.messagingService.send('locked', { userId: userId });
|
||||
|
||||
if (this.lockedCallback != null) {
|
||||
await this.lockedCallback();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ export class KeytarStorageListener {
|
||||
init() {
|
||||
ipcMain.on('keytar', async (event: any, message: any) => {
|
||||
try {
|
||||
console.debug('recieved message', message);
|
||||
let serviceName = this.serviceName;
|
||||
message.keySuffix = '_' + (message.keySuffix ?? '');
|
||||
if (message.keySuffix !== '_') {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { CryptoService } from 'jslib-common/services/crypto.service';
|
||||
|
||||
import { KeySuffixOptions } from 'jslib-common/enums/keySuffixOptions';
|
||||
import { StorageLocation } from 'jslib-common/enums/storageLocation';
|
||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
||||
|
||||
export class ElectronCryptoService extends CryptoService {
|
||||
|
||||
@@ -20,6 +21,20 @@ export class ElectronCryptoService extends CryptoService {
|
||||
return super.hasKeyStored(keySuffix);
|
||||
}
|
||||
|
||||
protected async storeKey(key: SymmetricCryptoKey, userId?: string) {
|
||||
if (await this.shouldStoreKey(KeySuffixOptions.Auto, userId)) {
|
||||
await this.stateService.setCryptoMasterKeyAuto(key.keyB64, { userId: userId });
|
||||
} else {
|
||||
this.clearStoredKey(KeySuffixOptions.Auto);
|
||||
}
|
||||
|
||||
if (await this.shouldStoreKey(KeySuffixOptions.Biometric, userId)) {
|
||||
await this.stateService.setCryptoMasterKeyBiometric(key.keyB64, { userId: userId });
|
||||
} else {
|
||||
this.clearStoredKey(KeySuffixOptions.Biometric);
|
||||
}
|
||||
}
|
||||
|
||||
protected async retrieveKeyFromStorage(keySuffix: KeySuffixOptions) {
|
||||
await this.upgradeSecurelyStoredKey();
|
||||
return super.retrieveKeyFromStorage(keySuffix);
|
||||
@@ -31,7 +46,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
*/
|
||||
private async upgradeSecurelyStoredKey() {
|
||||
// attempt key upgrade, but if we fail just delete it. Keys will be stored property upon unlock anyway.
|
||||
const key = await this.stateService.getCryptoMasterKey({ storageLocation: StorageLocation.Disk, useSecureStorage: true });
|
||||
const key = await this.stateService.getCryptoMasterKeyB64();
|
||||
|
||||
if (key == null) {
|
||||
return;
|
||||
@@ -49,6 +64,6 @@ export class ElectronCryptoService extends CryptoService {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
await this.stateService.setCryptoMasterKey(null, { storageLocation: StorageLocation.Disk, useSecureStorage: true });
|
||||
await this.stateService.setCryptoMasterKeyB64(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ export class ElectronRendererSecureStorageService implements StorageService {
|
||||
const val = ipcRenderer.sendSync('keytar', {
|
||||
action: 'getPassword',
|
||||
key: key,
|
||||
keySuffix: options?.keySuffix ?? '',
|
||||
});
|
||||
return Promise.resolve(val != null ? JSON.parse(val) as T : null);
|
||||
}
|
||||
@@ -17,6 +18,7 @@ export class ElectronRendererSecureStorageService implements StorageService {
|
||||
const val = ipcRenderer.sendSync('keytar', {
|
||||
action: 'hasPassword',
|
||||
key: key,
|
||||
keySuffix: options?.keySuffix ?? '',
|
||||
});
|
||||
return Promise.resolve(!!val);
|
||||
}
|
||||
@@ -25,6 +27,7 @@ export class ElectronRendererSecureStorageService implements StorageService {
|
||||
ipcRenderer.sendSync('keytar', {
|
||||
action: 'setPassword',
|
||||
key: key,
|
||||
keySuffix: options?.keySuffix ?? '',
|
||||
value: JSON.stringify(obj),
|
||||
});
|
||||
return Promise.resolve();
|
||||
@@ -34,6 +37,7 @@ export class ElectronRendererSecureStorageService implements StorageService {
|
||||
ipcRenderer.sendSync('keytar', {
|
||||
action: 'deletePassword',
|
||||
key: key,
|
||||
keySuffix: options?.keySuffix ?? '',
|
||||
});
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -25,8 +25,12 @@ export function isAppImage() {
|
||||
return process.platform === 'linux' && 'APPIMAGE' in process.env;
|
||||
}
|
||||
|
||||
export function isMac() {
|
||||
return process.platform === 'darwin';
|
||||
}
|
||||
|
||||
export function isMacAppStore() {
|
||||
return process.platform === 'darwin' && process.mas && process.mas === true;
|
||||
return isMac() && process.mas && process.mas === true;
|
||||
}
|
||||
|
||||
export function isWindowsStore() {
|
||||
|
||||
Reference in New Issue
Block a user