[SG-1016] Move MP confirmation to modal for encryptions settings changes (#4762)
* work: moving the form * fix: lint do be crazy sometimes * fix: remove debug stuff * fix: dialogService * per Danielle Flinn: option 1, leave sizing wide. * work: move modules to own container * work: reorg modules --------- Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com>
This commit is contained in:
parent
e90372cb5e
commit
0c84fcbcef
|
@ -0,0 +1,50 @@
|
|||
<bit-dialog>
|
||||
<span bitDialogTitle>
|
||||
{{ "changeKdf" | i18n }}
|
||||
</span>
|
||||
|
||||
<span bitDialogContent>
|
||||
<bit-callout type="warning">{{ "changeKdfLoggedOutWarning" | i18n }}</bit-callout>
|
||||
<form
|
||||
id="form"
|
||||
[formGroup]="form"
|
||||
(ngSubmit)="submit()"
|
||||
[appApiAction]="formPromise"
|
||||
ngNativeValidate
|
||||
autocomplete="off"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<bit-form-field class="tw-mb-1"
|
||||
><bit-label>{{ "masterPass" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
type="password"
|
||||
required
|
||||
formControlName="masterPassword"
|
||||
appAutofocus
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
bitSuffix
|
||||
bitIconButton
|
||||
bitPasswordInputToggle
|
||||
[(toggled)]="showPassword"
|
||||
></button
|
||||
><bit-hint>
|
||||
{{ "confirmIdentity" | i18n }}
|
||||
</bit-hint></bit-form-field
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</span>
|
||||
<div bitDialogFooter class="tw-flex tw-flex-row tw-gap-2">
|
||||
<button bitButton buttonType="primary" type="submit" [loading]="loading" form="form">
|
||||
<span>{{ "changeKdf" | i18n }}</span>
|
||||
</button>
|
||||
<button bitButton buttonType="secondary" type="button" data-dismiss="modal">
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</bit-dialog>
|
|
@ -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<any>;
|
||||
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;
|
||||
|
|
@ -2,23 +2,7 @@
|
|||
<h1>{{ "encKeySettings" | i18n }}</h1>
|
||||
</div>
|
||||
<bit-callout type="warning">{{ "changeKdfLoggedOutWarning" | i18n }}</bit-callout>
|
||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate autocomplete="off">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="form-group">
|
||||
<label for="kdfMasterPassword">{{ "masterPass" | i18n }}</label>
|
||||
<input
|
||||
id="kdfMasterPassword"
|
||||
type="password"
|
||||
name="MasterPasswordHash"
|
||||
class="form-control"
|
||||
[(ngModel)]="masterPassword"
|
||||
required
|
||||
appInputVerbatim
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form #form ngNativeValidate autocomplete="off">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="form-group mb-0">
|
||||
|
@ -122,7 +106,13 @@
|
|||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" buttonType="primary" bitButton [loading]="form.loading">
|
||||
<button
|
||||
(click)="openConfirmationModal()"
|
||||
type="button"
|
||||
buttonType="primary"
|
||||
bitButton
|
||||
[loading]="form.loading"
|
||||
>
|
||||
{{ "changeKdf" | i18n }}
|
||||
</button>
|
||||
</form>
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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 {}
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue