1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-24 20:23:24 +00:00

[PM-20225] Prevent legacy users without userkey from logging in (#14267)

* Prevent legacy users without userkey from logging in

* Remove further web-migration code for legacy users

* Add i18n for legacy user error message

* Update comment

* Remove migrate legacy component

* Remove i18n messages

* Remove migrate legacy encryption reference
This commit is contained in:
Bernd Schoolmann
2025-06-02 23:56:29 +02:00
committed by GitHub
parent 26caeb3083
commit 23ec6bacc9
19 changed files with 27 additions and 265 deletions

View File

@@ -1,2 +1 @@
export * from "./web-two-factor-auth-component.service";
export * from "./web-two-factor-auth-duo-component.service";

View File

@@ -1,14 +0,0 @@
import {
DefaultTwoFactorAuthComponentService,
TwoFactorAuthComponentService,
LegacyKeyMigrationAction,
} from "@bitwarden/auth/angular";
export class WebTwoFactorAuthComponentService
extends DefaultTwoFactorAuthComponentService
implements TwoFactorAuthComponentService
{
override determineLegacyKeyMigrationAction(): LegacyKeyMigrationAction {
return LegacyKeyMigrationAction.NAVIGATE_TO_MIGRATION_COMPONENT;
}
}

View File

@@ -32,7 +32,6 @@ import {
SetPasswordJitService,
SsoComponentService,
LoginDecryptionOptionsService,
TwoFactorAuthComponentService,
TwoFactorAuthDuoComponentService,
ChangePasswordService,
} from "@bitwarden/auth/angular";
@@ -116,7 +115,6 @@ import {
WebRegistrationFinishService,
WebLoginComponentService,
WebLoginDecryptionOptionsService,
WebTwoFactorAuthComponentService,
WebTwoFactorAuthDuoComponentService,
LinkSsoService,
} from "../auth";
@@ -269,12 +267,6 @@ const safeProviders: SafeProvider[] = [
useClass: WebLockComponentService,
deps: [],
}),
// TODO: PM-18182 - Refactor component services into lazy loaded modules
safeProvider({
provide: TwoFactorAuthComponentService,
useClass: WebTwoFactorAuthComponentService,
deps: [],
}),
safeProvider({
provide: SetPasswordJitService,
useClass: WebSetPasswordJitService,

View File

@@ -1,36 +0,0 @@
<form [formGroup]="formGroup" [bitSubmit]="submit">
<div class="tw-mt-12 tw-flex tw-justify-center">
<div class="tw-max-w-xl">
<h1 bitTypography="h1" class="tw-mb-4 tw-text-center">{{ "updateEncryptionKey" | i18n }}</h1>
<div
class="tw-block tw-rounded tw-border tw-border-solid tw-border-secondary-300 tw-bg-background tw-p-8"
>
<p>
{{ "updateEncryptionSchemeDesc" | i18n }}
<a
href="https://bitwarden.com/help/account-encryption-key/#rotate-your-encryption-key"
target="_blank"
rel="noreferrer"
>{{ "learnMore" | i18n }}</a
>
</p>
<bit-callout type="warning">{{ "updateEncryptionKeyWarning" | i18n }}</bit-callout>
<bit-form-field>
<bit-label>{{ "masterPass" | i18n }}</bit-label>
<input
id="masterPassword"
bitInput
type="password"
formControlName="masterPassword"
appAutofocus
/>
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
</bit-form-field>
<button type="submit" bitButton bitFormButton buttonType="primary" block>
{{ "updateEncryptionKey" | i18n }}
</button>
</div>
</div>
</div>
</form>

View File

@@ -1,100 +0,0 @@
import { Component } from "@angular/core";
import { FormControl, FormGroup, Validators } from "@angular/forms";
import { firstValueFrom } from "rxjs";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { DialogService, ToastService } from "@bitwarden/components";
import { KeyService } from "@bitwarden/key-management";
import { SharedModule } from "../../shared";
import { UserKeyRotationModule } from "../key-rotation/user-key-rotation.module";
import { UserKeyRotationService } from "../key-rotation/user-key-rotation.service";
// The master key was originally used to encrypt user data, before the user key was introduced.
// This component is used to migrate from the old encryption scheme to the new one.
@Component({
imports: [SharedModule, UserKeyRotationModule],
templateUrl: "migrate-legacy-encryption.component.html",
})
export class MigrateFromLegacyEncryptionComponent {
protected formGroup = new FormGroup({
masterPassword: new FormControl("", [Validators.required]),
});
constructor(
private accountService: AccountService,
private keyRotationService: UserKeyRotationService,
private i18nService: I18nService,
private keyService: KeyService,
private messagingService: MessagingService,
private logService: LogService,
private syncService: SyncService,
private toastService: ToastService,
private dialogService: DialogService,
private folderApiService: FolderApiServiceAbstraction,
) {}
submit = async () => {
this.formGroup.markAsTouched();
if (this.formGroup.invalid) {
return;
}
const activeUser = await firstValueFrom(this.accountService.activeAccount$);
if (activeUser == null) {
throw new Error("No active user.");
}
const hasUserKey = await this.keyService.hasUserKey(activeUser.id);
if (hasUserKey) {
this.messagingService.send("logout");
throw new Error("User key already exists, cannot migrate legacy encryption.");
}
const masterPassword = this.formGroup.value.masterPassword!;
try {
await this.syncService.fullSync(false, true);
await this.keyRotationService.rotateUserKeyAndEncryptedDataLegacy(masterPassword, activeUser);
this.toastService.showToast({
variant: "success",
title: this.i18nService.t("keyUpdated"),
message: this.i18nService.t("logBackInOthersToo"),
timeout: 15000,
});
this.messagingService.send("logout");
} catch (e) {
// If the error is due to missing folders, we can delete all folders and try again
if (
e instanceof ErrorResponse &&
e.message === "All existing folders must be included in the rotation."
) {
const deleteFolders = await this.dialogService.openSimpleDialog({
type: "warning",
title: { key: "encryptionKeyUpdateCannotProceed" },
content: { key: "keyUpdateFoldersFailed" },
acceptButtonText: { key: "ok" },
cancelButtonText: { key: "cancel" },
});
if (deleteFolders) {
await this.folderApiService.deleteAll(activeUser.id);
await this.syncService.fullSync(true, true);
await this.submit();
return;
}
}
this.logService.error(e);
throw e;
}
};
}

View File

@@ -151,13 +151,6 @@ const routes: Routes = [
canActivate: [authGuard],
data: { titleId: "updatePassword" } satisfies RouteDataProperties,
},
{
path: "migrate-legacy-encryption",
loadComponent: () =>
import("./key-management/migrate-encryption/migrate-legacy-encryption.component").then(
(mod) => mod.MigrateFromLegacyEncryptionComponent,
),
},
],
},
{