Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-3726] Force migration of legacy user's encryption key #6195

Merged
merged 14 commits into from
Sep 20, 2023
Merged
2 changes: 1 addition & 1 deletion libs/angular/src/auth/guards/lock.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function lockGuard(): CanActivateFn {
const userVerificationService = inject(UserVerificationService);

// If legacy user on web, redirect to migration page
if (cryptoService.isLegacyUser()) {
if (await cryptoService.isLegacyUser()) {
if (platformUtilService.getClientType() === ClientType.Web) {
return router.createUrlTree(["migrate-legacy-encryption"]);
}
Expand Down
39 changes: 23 additions & 16 deletions libs/common/src/platform/services/crypto.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -950,23 +950,30 @@ export class CryptoService implements CryptoServiceAbstraction {

async migrateAutoKeyIfNeeded(userId?: string) {
const oldAutoKey = await this.stateService.getCryptoMasterKeyAuto({ userId: userId });
if (oldAutoKey) {
// decrypt
const masterKey = new SymmetricCryptoKey(Utils.fromB64ToArray(oldAutoKey)) as MasterKey;
const encryptedUserKey = await this.stateService.getEncryptedCryptoSymmetricKey({
userId: userId,
});
const userKey = await this.decryptUserKeyWithMasterKey(
masterKey,
new EncString(encryptedUserKey),
userId
);
// migrate
await this.stateService.setUserKeyAutoUnlock(userKey.keyB64, { userId: userId });
await this.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
// set encrypted user key in case user immediately locks without syncing
await this.setMasterKeyEncryptedUserKey(encryptedUserKey);
if (!oldAutoKey) {
return;
}
// Decrypt
const masterKey = new SymmetricCryptoKey(Utils.fromB64ToArray(oldAutoKey)) as MasterKey;
if (await this.isLegacyUser(masterKey, userId)) {
// Legacy users don't have a user key, so no need to migrate.
// Instead, set the master key for additional isLegacyUser checks that will log the user out.
await this.setMasterKey(masterKey, userId);
return;
}
const encryptedUserKey = await this.stateService.getEncryptedCryptoSymmetricKey({
userId: userId,
});
const userKey = await this.decryptUserKeyWithMasterKey(
masterKey,
new EncString(encryptedUserKey),
userId
);
// Migrate
await this.stateService.setUserKeyAutoUnlock(userKey.keyB64, { userId: userId });
await this.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
// Set encrypted user key in case user immediately locks without syncing
await this.setMasterKeyEncryptedUserKey(encryptedUserKey);
}

async decryptAndMigrateOldPinKey(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/va
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "../../abstractions/vault-timeout/vault-timeout.service";
import { AuthService } from "../../auth/abstractions/auth.service";
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
import { ClientType } from "../../enums";
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { MessagingService } from "../../platform/abstractions/messaging.service";
Expand Down Expand Up @@ -141,10 +142,18 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
}

private async migrateKeyForNeverLockIfNeeded(): Promise<void> {
// Web can't set vault timeout to never
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically we can in dev mode.

if (this.platformUtilsService.getClientType() == ClientType.Web) {
return;
}
const accounts = await firstValueFrom(this.stateService.accounts$);
for (const userId in accounts) {
if (userId != null) {
await this.cryptoService.migrateAutoKeyIfNeeded(userId);
// Legacy users should be logged out since we're not on the web vault and can't migrate.
JaredSnider-Bitwarden marked this conversation as resolved.
Show resolved Hide resolved
if (await this.cryptoService.isLegacyUser(null, userId)) {
await this.logOut(userId);
}
}
}
}
Expand Down