diff --git a/apps/web/src/app/settings/change-kdf/change-kdf-confirmation.component.html b/apps/web/src/app/settings/change-kdf/change-kdf-confirmation.component.html new file mode 100644 index 0000000000..df5c5c275f --- /dev/null +++ b/apps/web/src/app/settings/change-kdf/change-kdf-confirmation.component.html @@ -0,0 +1,50 @@ + + + {{ "changeKdf" | i18n }} + + + + {{ "changeKdfLoggedOutWarning" | i18n }} +
+
+
+ {{ "masterPass" | i18n }} + + + {{ "confirmIdentity" | i18n }} + +
+
+
+
+
+ + +
+
diff --git a/apps/web/src/app/settings/change-kdf.component.ts b/apps/web/src/app/settings/change-kdf/change-kdf-confirmation.component.ts similarity index 62% rename from apps/web/src/app/settings/change-kdf.component.ts rename to apps/web/src/app/settings/change-kdf/change-kdf-confirmation.component.ts index c11d127c0e..9e56fe6b3d 100644 --- a/apps/web/src/app/settings/change-kdf.component.ts +++ b/apps/web/src/app/settings/change-kdf/change-kdf-confirmation.component.ts @@ -1,4 +1,6 @@ -import { Component, OnInit } from "@angular/core"; +import { DIALOG_DATA } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; +import { FormGroup, FormControl, Validators } from "@angular/forms"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; @@ -8,28 +10,24 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; -import { - DEFAULT_KDF_CONFIG, - DEFAULT_PBKDF2_ITERATIONS, - DEFAULT_ARGON2_ITERATIONS, - DEFAULT_ARGON2_MEMORY, - DEFAULT_ARGON2_PARALLELISM, - KdfType, -} from "@bitwarden/common/enums/kdfType"; +import { KdfType } from "@bitwarden/common/enums/kdfType"; import { KdfRequest } from "@bitwarden/common/models/request/kdf.request"; @Component({ - selector: "app-change-kdf", - templateUrl: "change-kdf.component.html", + selector: "app-change-kdf-confirmation", + templateUrl: "change-kdf-confirmation.component.html", }) -export class ChangeKdfComponent implements OnInit { +export class ChangeKdfConfirmationComponent { + kdf: KdfType; + kdfConfig: KdfConfig; + + form = new FormGroup({ + masterPassword: new FormControl(null, Validators.required), + }); + showPassword = false; masterPassword: string; - kdf = KdfType.PBKDF2_SHA256; - kdfConfig: KdfConfig = DEFAULT_KDF_CONFIG; - kdfType = KdfType; - kdfOptions: any[] = []; formPromise: Promise; - recommendedPbkdf2Iterations = DEFAULT_PBKDF2_ITERATIONS; + loading = false; constructor( private apiService: ApiService, @@ -37,21 +35,17 @@ export class ChangeKdfComponent implements OnInit { private platformUtilsService: PlatformUtilsService, private cryptoService: CryptoService, private messagingService: MessagingService, + private stateService: StateService, private logService: LogService, - private stateService: StateService + @Inject(DIALOG_DATA) params: { kdf: KdfType; kdfConfig: KdfConfig } ) { - this.kdfOptions = [ - { name: "PBKDF2 SHA-256", value: KdfType.PBKDF2_SHA256 }, - { name: "Argon2id", value: KdfType.Argon2id }, - ]; - } - - async ngOnInit() { - this.kdf = await this.stateService.getKdfType(); - this.kdfConfig = await this.stateService.getKdfConfig(); + this.kdf = params.kdf; + this.kdfConfig = params.kdfConfig; + this.masterPassword = null; } async submit() { + this.loading = true; const hasEncKey = await this.cryptoService.hasEncKey(); if (!hasEncKey) { this.platformUtilsService.showToast("error", null, this.i18nService.t("updateKey")); @@ -69,41 +63,27 @@ export class ChangeKdfComponent implements OnInit { this.messagingService.send("logout"); } catch (e) { this.logService.error(e); - } - } - - async onChangeKdf(newValue: KdfType) { - if (newValue === KdfType.PBKDF2_SHA256) { - this.kdfConfig = new KdfConfig(DEFAULT_PBKDF2_ITERATIONS); - } else if (newValue === KdfType.Argon2id) { - this.kdfConfig = new KdfConfig( - DEFAULT_ARGON2_ITERATIONS, - DEFAULT_ARGON2_MEMORY, - DEFAULT_ARGON2_PARALLELISM - ); - } else { - throw new Error("Unknown KDF type."); + } finally { + this.loading = false; } } private async makeKeyAndSaveAsync() { + const masterPassword = this.form.value.masterPassword; const request = new KdfRequest(); request.kdf = this.kdf; request.kdfIterations = this.kdfConfig.iterations; request.kdfMemory = this.kdfConfig.memory; request.kdfParallelism = this.kdfConfig.parallelism; - request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, null); + request.masterPasswordHash = await this.cryptoService.hashPassword(masterPassword, null); const email = await this.stateService.getEmail(); const newKey = await this.cryptoService.makeKey( - this.masterPassword, + masterPassword, email, this.kdf, this.kdfConfig ); - request.newMasterPasswordHash = await this.cryptoService.hashPassword( - this.masterPassword, - newKey - ); + request.newMasterPasswordHash = await this.cryptoService.hashPassword(masterPassword, newKey); const newEncKey = await this.cryptoService.remakeEncKey(newKey); request.key = newEncKey[1].encryptedString; diff --git a/apps/web/src/app/settings/change-kdf.component.html b/apps/web/src/app/settings/change-kdf/change-kdf.component.html similarity index 85% rename from apps/web/src/app/settings/change-kdf.component.html rename to apps/web/src/app/settings/change-kdf/change-kdf.component.html index e9d13e375f..0411c37380 100644 --- a/apps/web/src/app/settings/change-kdf.component.html +++ b/apps/web/src/app/settings/change-kdf/change-kdf.component.html @@ -2,23 +2,7 @@

{{ "encKeySettings" | i18n }}

{{ "changeKdfLoggedOutWarning" | i18n }} -
-
-
-
- - -
-
-
+
@@ -122,7 +106,13 @@
- diff --git a/apps/web/src/app/settings/change-kdf/change-kdf.component.ts b/apps/web/src/app/settings/change-kdf/change-kdf.component.ts new file mode 100644 index 0000000000..15fd6fda12 --- /dev/null +++ b/apps/web/src/app/settings/change-kdf/change-kdf.component.ts @@ -0,0 +1,62 @@ +import { Component, OnInit } from "@angular/core"; + +import { StateService } from "@bitwarden/common/abstractions/state.service"; +import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; +import { + DEFAULT_KDF_CONFIG, + DEFAULT_PBKDF2_ITERATIONS, + DEFAULT_ARGON2_ITERATIONS, + DEFAULT_ARGON2_MEMORY, + DEFAULT_ARGON2_PARALLELISM, + KdfType, +} from "@bitwarden/common/enums/kdfType"; +import { DialogService } from "@bitwarden/components"; + +import { ChangeKdfConfirmationComponent } from "./change-kdf-confirmation.component"; + +@Component({ + selector: "app-change-kdf", + templateUrl: "change-kdf.component.html", +}) +export class ChangeKdfComponent implements OnInit { + kdf = KdfType.PBKDF2_SHA256; + kdfConfig: KdfConfig = DEFAULT_KDF_CONFIG; + kdfType = KdfType; + kdfOptions: any[] = []; + recommendedPbkdf2Iterations = DEFAULT_PBKDF2_ITERATIONS; + + constructor(private stateService: StateService, private dialogService: DialogService) { + this.kdfOptions = [ + { name: "PBKDF2 SHA-256", value: KdfType.PBKDF2_SHA256 }, + { name: "Argon2id", value: KdfType.Argon2id }, + ]; + } + + async ngOnInit() { + this.kdf = await this.stateService.getKdfType(); + this.kdfConfig = await this.stateService.getKdfConfig(); + } + + async onChangeKdf(newValue: KdfType) { + if (newValue === KdfType.PBKDF2_SHA256) { + this.kdfConfig = new KdfConfig(DEFAULT_PBKDF2_ITERATIONS); + } else if (newValue === KdfType.Argon2id) { + this.kdfConfig = new KdfConfig( + DEFAULT_ARGON2_ITERATIONS, + DEFAULT_ARGON2_MEMORY, + DEFAULT_ARGON2_PARALLELISM + ); + } else { + throw new Error("Unknown KDF type."); + } + } + + async openConfirmationModal() { + this.dialogService.open(ChangeKdfConfirmationComponent, { + data: { + kdf: this.kdf, + kdfConfig: this.kdfConfig, + }, + }); + } +} diff --git a/apps/web/src/app/settings/change-kdf/change-kdf.module.ts b/apps/web/src/app/settings/change-kdf/change-kdf.module.ts new file mode 100644 index 0000000000..342ad43e36 --- /dev/null +++ b/apps/web/src/app/settings/change-kdf/change-kdf.module.ts @@ -0,0 +1,14 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; + +import { SharedModule } from "../../shared"; + +import { ChangeKdfConfirmationComponent } from "./change-kdf-confirmation.component"; +import { ChangeKdfComponent } from "./change-kdf.component"; + +@NgModule({ + imports: [CommonModule, SharedModule], + declarations: [ChangeKdfComponent, ChangeKdfConfirmationComponent], + exports: [ChangeKdfComponent, ChangeKdfConfirmationComponent], +}) +export class ChangeKdfModule {} diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index cc7ae66104..7b988acc51 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -74,7 +74,7 @@ import { BillingHistoryComponent } from "../settings/billing-history.component"; import { BillingSyncKeyComponent } from "../settings/billing-sync-key.component"; import { ChangeAvatarComponent } from "../settings/change-avatar.component"; import { ChangeEmailComponent } from "../settings/change-email.component"; -import { ChangeKdfComponent } from "../settings/change-kdf.component"; +import { ChangeKdfModule } from "../settings/change-kdf/change-kdf.module"; import { ChangePasswordComponent } from "../settings/change-password.component"; import { CreateOrganizationComponent } from "../settings/create-organization.component"; import { DeleteAccountComponent } from "../settings/delete-account.component"; @@ -117,7 +117,13 @@ import { SharedModule } from "./shared.module"; // Please do not add to this list of declarations - we should refactor these into modules when doing so makes sense until there are none left. // If you are building new functionality, please create or extend a feature module instead. @NgModule({ - imports: [SharedModule, OrganizationCreateModule, RegisterFormModule, ProductSwitcherModule], + imports: [ + SharedModule, + OrganizationCreateModule, + RegisterFormModule, + ProductSwitcherModule, + ChangeKdfModule, + ], declarations: [ PremiumBadgeComponent, AcceptEmergencyComponent, @@ -135,7 +141,6 @@ import { SharedModule } from "./shared.module"; AttachmentsComponent, BillingSyncKeyComponent, ChangeEmailComponent, - ChangeKdfComponent, ChangePasswordComponent, CollectionsComponent, CreateOrganizationComponent, @@ -245,7 +250,6 @@ import { SharedModule } from "./shared.module"; ApiKeyComponent, AttachmentsComponent, ChangeEmailComponent, - ChangeKdfComponent, ChangePasswordComponent, CollectionsComponent, CreateOrganizationComponent, diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 3910581d45..013f6fa6bc 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -6491,7 +6491,7 @@ "message": "Change KDF settings" }, "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManagerBeta": { "message": "Secrets Manager Beta"