1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-20 02:03:39 +00:00

merge main, fix conflicts

This commit is contained in:
rr-bw
2024-09-13 10:05:57 -07:00
323 changed files with 6478 additions and 1448 deletions

View File

@@ -1,9 +1,12 @@
<!-- The calc() reductions are to account for browser/desktop headers -->
<main
class="tw-flex tw-min-h-screen tw-w-full tw-mx-auto tw-flex-col tw-gap-7 tw-bg-background-alt tw-px-8 tw-pb-4 tw-text-main"
class="tw-flex tw-w-full tw-mx-auto tw-flex-col tw-gap-7 tw-bg-background-alt tw-px-8 tw-pb-4 tw-text-main"
[ngClass]="{
'tw-pt-0': decreaseTopPadding,
'tw-pt-8': !decreaseTopPadding,
'tw-relative tw-top-0': clientType === 'browser',
'tw-min-h-screen': clientType === 'web',
'tw-min-h-[calc(100vh-72px)]': clientType === 'browser',
'tw-min-h-[calc(100vh-54px)]': clientType === 'desktop',
}"
>
<bit-icon *ngIf="!hideLogo" [icon]="logo" class="tw-w-[128px] [&>*]:tw-align-top"></bit-icon>
@@ -23,6 +26,7 @@
{{ title }}
</h1>
</ng-container>
<div *ngIf="subtitle" class="tw-text-sm sm:tw-text-base">{{ subtitle }}</div>
</div>

View File

@@ -3,5 +3,6 @@ export * from "./bitwarden-shield.icon";
export * from "./lock.icon";
export * from "./registration-check-email.icon";
export * from "./registration-expired-link.icon";
export * from "./user-lock.icon";
export * from "./user-verification-biometrics-fingerprint.icon";
export * from "./wave.icon";

View File

@@ -2,16 +2,16 @@ import { svgIcon } from "@bitwarden/components";
export const LockIcon = svgIcon`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 100" fill="none">
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M27.5 48.218a9 9 0 0 1 9-9h47a9 9 0 0 1 9 9v7.5h-2v-7.5a7 7 0 0 0-7-7h-47a7 7 0 0 0-7 7v7.5h-2v-7.5Zm2 30.75v3.75a7 7 0 0 0 7 7h47a7 7 0 0 0 7-7v-3.75h2v3.75a9 9 0 0 1-9 9h-47a9 9 0 0 1-9-9v-3.75h2Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M60 10.718c-11.144 0-20 7.942-20 17.414v11.586h-2V28.132C38 17.317 48.007 8.718 60 8.718c11.991 0 22 8.552 22 19.414v11.586h-2V28.132c0-9.516-8.855-17.414-20-17.414ZM32.028 61.28a1 1 0 0 1 1 1v5.678a1 1 0 1 1-2 0v-5.679a1 1 0 0 1 1-1Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M38.452 65.897a1 1 0 0 1-.647 1.258l-5.472 1.755a1 1 0 1 1-.61-1.904l5.471-1.755a1 1 0 0 1 1.258.646Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M31.442 67.147a1 1 0 0 1 1.396.225l3.356 4.646a1 1 0 0 1-1.622 1.171l-3.355-4.646a1 1 0 0 1 .225-1.396Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M32.607 67.143a1 1 0 0 1 .236 1.394l-3.304 4.646a1 1 0 0 1-1.63-1.159l3.304-4.646a1 1 0 0 1 1.394-.235Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M25.656 65.895a1 1 0 0 1 1.26-.644l5.42 1.755a1 1 0 1 1-.616 1.903l-5.42-1.755a1 1 0 0 1-.644-1.26ZM50.508 61.28a1 1 0 0 1 1 1v5.678a1 1 0 1 1-2 0v-5.679a1 1 0 0 1 1-1Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M56.88 65.895a1 1 0 0 1-.644 1.26l-5.42 1.754a1 1 0 1 1-.616-1.903l5.42-1.755a1 1 0 0 1 1.26.644Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M49.922 67.147a1 1 0 0 1 1.397.225l3.355 4.646a1 1 0 1 1-1.621 1.171l-3.356-4.646a1 1 0 0 1 .225-1.396Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M51.093 67.147a1 1 0 0 1 .226 1.396l-3.356 4.646a1 1 0 0 1-1.621-1.17l3.355-4.647a1 1 0 0 1 1.396-.225Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M44.136 65.895a1 1 0 0 1 1.26-.644l5.42 1.755a1 1 0 1 1-.616 1.903l-5.42-1.755a1 1 0 0 1-.644-1.26ZM62.568 72.603a1 1 0 0 1 1-1h10.84a1 1 0 1 1 0 2h-10.84a1 1 0 0 1-1-1ZM81.049 72.603a1 1 0 0 1 1-1h10.84a1 1 0 1 1 0 2H82.05a1 1 0 0 1-1-1Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M17.5 67.468c0-7.042 5.708-12.75 12.75-12.75h59.5c7.041 0 12.75 5.708 12.75 12.75s-5.709 12.75-12.75 12.75h-59.5c-7.042 0-12.75-5.708-12.75-12.75Zm12.75-10.75c-5.937 0-10.75 4.813-10.75 10.75s4.813 10.75 10.75 10.75h59.5c5.937 0 10.75-4.813 10.75-10.75s-4.813-10.75-10.75-10.75h-59.5Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M27.5 48.218a9 9 0 0 1 9-9h47a9 9 0 0 1 9 9v7.5h-2v-7.5a7 7 0 0 0-7-7h-47a7 7 0 0 0-7 7v7.5h-2v-7.5Zm2 30.75v3.75a7 7 0 0 0 7 7h47a7 7 0 0 0 7-7v-3.75h2v3.75a9 9 0 0 1-9 9h-47a9 9 0 0 1-9-9v-3.75h2Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M60 10.718c-11.144 0-20 7.942-20 17.414v11.586h-2V28.132C38 17.317 48.007 8.718 60 8.718c11.991 0 22 8.552 22 19.414v11.586h-2V28.132c0-9.516-8.855-17.414-20-17.414ZM32.028 61.28a1 1 0 0 1 1 1v5.678a1 1 0 1 1-2 0v-5.679a1 1 0 0 1 1-1Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M38.452 65.897a1 1 0 0 1-.647 1.258l-5.472 1.755a1 1 0 1 1-.61-1.904l5.471-1.755a1 1 0 0 1 1.258.646Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M31.442 67.147a1 1 0 0 1 1.396.225l3.356 4.646a1 1 0 0 1-1.622 1.171l-3.355-4.646a1 1 0 0 1 .225-1.396Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M32.607 67.143a1 1 0 0 1 .236 1.394l-3.304 4.646a1 1 0 0 1-1.63-1.159l3.304-4.646a1 1 0 0 1 1.394-.235Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M25.656 65.895a1 1 0 0 1 1.26-.644l5.42 1.755a1 1 0 1 1-.616 1.903l-5.42-1.755a1 1 0 0 1-.644-1.26ZM50.508 61.28a1 1 0 0 1 1 1v5.678a1 1 0 1 1-2 0v-5.679a1 1 0 0 1 1-1Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M56.88 65.895a1 1 0 0 1-.644 1.26l-5.42 1.754a1 1 0 1 1-.616-1.903l5.42-1.755a1 1 0 0 1 1.26.644Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M49.922 67.147a1 1 0 0 1 1.397.225l3.355 4.646a1 1 0 1 1-1.621 1.171l-3.356-4.646a1 1 0 0 1 .225-1.396Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M51.093 67.147a1 1 0 0 1 .226 1.396l-3.356 4.646a1 1 0 0 1-1.621-1.17l3.355-4.647a1 1 0 0 1 1.396-.225Z" clip-rule="evenodd"/>
<path class="tw-fill-art-primary" fill-rule="evenodd" d="M44.136 65.895a1 1 0 0 1 1.26-.644l5.42 1.755a1 1 0 1 1-.616 1.903l-5.42-1.755a1 1 0 0 1-.644-1.26ZM62.568 72.603a1 1 0 0 1 1-1h10.84a1 1 0 1 1 0 2h-10.84a1 1 0 0 1-1-1ZM81.049 72.603a1 1 0 0 1 1-1h10.84a1 1 0 1 1 0 2H82.05a1 1 0 0 1-1-1Z" clip-rule="evenodd"/>
<path class="tw-fill-art-accent" fill-rule="evenodd" d="M17.5 67.468c0-7.042 5.708-12.75 12.75-12.75h59.5c7.041 0 12.75 5.708 12.75 12.75s-5.709 12.75-12.75 12.75h-59.5c-7.042 0-12.75-5.708-12.75-12.75Zm12.75-10.75c-5.937 0-10.75 4.813-10.75 10.75s4.813 10.75 10.75 10.75h59.5c5.937 0 10.75-4.813 10.75-10.75s-4.813-10.75-10.75-10.75h-59.5Z" clip-rule="evenodd"/>
</svg>
`;

View File

@@ -0,0 +1,22 @@
import { svgIcon } from "@bitwarden/components";
export const UserLockIcon = svgIcon`
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="100" fill="none">
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M0 18.207a7.798 7.798 0 0 1 7.798-7.798H89.38a7.798 7.798 0 0 1 7.799 7.798v8.763h-2.4v-8.763a5.399 5.399 0 0 0-5.398-5.399H7.797A5.399 5.399 0 0 0 2.4 18.207v49.19a5.399 5.399 0 0 0 5.4 5.398h9.483v2.4H7.798A7.798 7.798 0 0 1 0 67.396V18.207Zm49.378 54.588h13.498v2.4H49.378v-2.4Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M88.78 58.398c8.946 0 16.197-7.251 16.197-16.196s-7.251-16.197-16.196-16.197-16.197 7.252-16.197 16.197 7.252 16.196 16.197 16.196Zm0 2.4c10.27 0 18.597-8.326 18.597-18.596s-8.326-18.596-18.596-18.596-18.596 8.326-18.596 18.596S78.51 60.798 88.78 60.798Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M61.005 87.192h54.28c1.303 0 1.833-.344 2.01-.53.128-.134.396-.517.226-1.586-2.187-13.74-14.213-24.278-28.752-24.278S62.203 71.337 60.017 85.076c-.09.57.026 1.226.279 1.662.115.2.23.305.316.359.072.046.184.095.393.095Zm0 2.4h54.28c3.346 0 5.104-1.76 4.605-4.893-2.371-14.903-15.402-26.3-31.121-26.3-15.72 0-28.75 11.397-31.122 26.3-.337 2.121.744 4.893 3.358 4.893Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M77.983 17.607a1.2 1.2 0 0 1-1.2-1.2v-.6a1.2 1.2 0 1 1 2.4 0v.6a1.2 1.2 0 0 1-1.2 1.2ZM83.382 17.607a1.2 1.2 0 0 1-1.2-1.2v-.498a1.2 1.2 0 1 1 2.4 0v.498a1.2 1.2 0 0 1-1.2 1.2ZM88.78 17.607a1.2 1.2 0 0 1-1.2-1.2v-.498a1.2 1.2 0 1 1 2.4 0v.498a1.2 1.2 0 0 1-1.2 1.2Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M95.083 20.607H0v-1.2h95.083v1.2ZM15.12 54.571a5.999 5.999 0 0 1 6-5.998h23.23a5.999 5.999 0 0 1 6 5.998V57.2h-2.4V54.57a3.6 3.6 0 0 0-3.6-3.599H21.12a3.6 3.6 0 0 0-3.6 3.6v2.627h-2.4V54.57Zm2.4 15.825v2.693a3.6 3.6 0 0 0 3.6 3.599h23.23a3.6 3.6 0 0 0 3.6-3.6v-2.692h2.4v2.693a5.999 5.999 0 0 1-6 5.998H21.12a5.999 5.999 0 0 1-6-5.998v-2.693h2.4Z" clip-rule="evenodd"/>
<path class="tw-fill-text-headers" fill-rule="evenodd" d="M32.479 33.255c-5.31 0-9.641 4.332-9.641 9.64v6.822h-2.4v-6.821c0-6.635 5.406-12.04 12.04-12.04 6.633 0 12.041 5.377 12.041 12.04v6.821h-2.4v-6.821c0-5.334-4.33-9.641-9.64-9.641Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M10.498 63.797a7.498 7.498 0 0 1 7.498-7.498h30.593a7.498 7.498 0 0 1 0 14.997H17.996a7.498 7.498 0 0 1-7.498-7.499Zm43.79 0a5.699 5.699 0 0 0-5.699-5.699H17.996a5.699 5.699 0 0 0 0 11.398h30.593a5.699 5.699 0 0 0 5.7-5.699Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M19.02 60.669a.6.6 0 0 1 .6.6v2.959a.6.6 0 0 1-1.2 0v-2.96a.6.6 0 0 1 .6-.6Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M22.443 63.13a.6.6 0 0 1-.388.755l-2.851.914a.6.6 0 1 1-.367-1.142l2.852-.915a.6.6 0 0 1 .754.388Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M18.67 63.742a.6.6 0 0 1 .837.135l1.748 2.42a.6.6 0 0 1-.972.703l-1.749-2.42a.6.6 0 0 1 .136-.838Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M19.368 63.739a.6.6 0 0 1 .142.837l-1.722 2.42a.6.6 0 0 1-.978-.695l1.722-2.42a.6.6 0 0 1 .836-.142Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M15.626 63.129a.6.6 0 0 1 .755-.386l2.825.914a.6.6 0 0 1-.37 1.142l-2.824-.915a.6.6 0 0 1-.386-.755ZM28.651 60.669a.6.6 0 0 1 .6.6v2.959a.6.6 0 1 1-1.2 0v-2.96a.6.6 0 0 1 .6-.6Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M32.046 63.129a.6.6 0 0 1-.386.755l-2.824.915a.6.6 0 1 1-.37-1.142l2.825-.914a.6.6 0 0 1 .755.386Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M28.3 63.742a.6.6 0 0 1 .837.135l1.749 2.42a.6.6 0 0 1-.973.703l-1.748-2.42a.6.6 0 0 1 .135-.838Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M29.002 63.742a.6.6 0 0 1 .136.837L27.387 67a.6.6 0 0 1-.972-.702l1.749-2.421a.6.6 0 0 1 .837-.136Z" clip-rule="evenodd"/>
<path class="tw-fill-info-600" fill-rule="evenodd" d="M25.256 63.129a.6.6 0 0 1 .755-.386l2.825.914a.6.6 0 1 1-.37 1.142l-2.824-.915a.6.6 0 0 1-.386-.755ZM34.857 66.649a.6.6 0 0 1 .6-.6h5.649a.6.6 0 0 1 0 1.2h-5.649a.6.6 0 0 1-.6-.6ZM44.487 66.649a.6.6 0 0 1 .6-.6h5.65a.6.6 0 0 1 0 1.2h-5.65a.6.6 0 0 1-.6-.6Z" clip-rule="evenodd"/>
</svg>
`;

View File

@@ -27,6 +27,9 @@ export * from "./login/default-login.service";
// password callout
export * from "./password-callout/password-callout.component";
// password hint
export * from "./password-hint/password-hint.component";
// registration
export * from "./registration/registration-start/registration-start.component";
export * from "./registration/registration-finish/registration-finish.component";

View File

@@ -0,0 +1,40 @@
<form [bitSubmit]="submit" [formGroup]="formGroup">
<!-- <ng-template> must be within the <form> to ensure that `formControlName` has a parent `formGroup` directive. -->
<ng-template #formContentTemplate>
<bit-form-field>
<bit-label>{{ "accountEmail" | i18n }}</bit-label>
<input
bitInput
appAutofocus
inputmode="email"
appInputVerbatim="false"
type="email"
formControlName="email"
/>
</bit-form-field>
<button
class="tw-mb-2"
type="submit"
bitButton
bitFormButton
buttonType="primary"
[block]="true"
>
{{ "requestHint" | i18n }}
</button>
<button type="button" bitButton buttonType="secondary" (click)="cancel()" [block]="true">
{{ "cancel" | i18n }}
</button>
</ng-template>
<!-- Browser -->
<main *ngIf="clientType === 'browser'" tabindex="-1">
<ng-container *ngTemplateOutlet="formContentTemplate"></ng-container>
</main>
<!-- Web, Desktop -->
<ng-container *ngIf="clientType !== 'browser'">
<ng-container *ngTemplateOutlet="formContentTemplate"></ng-container>
</ng-container>
</form>

View File

@@ -0,0 +1,107 @@
import { CommonModule } from "@angular/common";
import { Component, OnInit } from "@angular/core";
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
import { Router, RouterModule } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { LoginEmailServiceAbstraction } from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { PasswordHintRequest } from "@bitwarden/common/auth/models/request/password-hint.request";
import { ClientType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import {
AsyncActionsModule,
ButtonModule,
FormFieldModule,
ToastService,
} from "@bitwarden/components";
@Component({
standalone: true,
templateUrl: "./password-hint.component.html",
imports: [
AsyncActionsModule,
ButtonModule,
CommonModule,
FormFieldModule,
JslibModule,
ReactiveFormsModule,
RouterModule,
],
})
export class PasswordHintComponent implements OnInit {
protected clientType: ClientType;
protected formGroup = this.formBuilder.group({
email: ["", [Validators.required, Validators.email]],
});
protected get email() {
return this.formGroup.controls.email.value;
}
constructor(
private apiService: ApiService,
private formBuilder: FormBuilder,
private i18nService: I18nService,
private loginEmailService: LoginEmailServiceAbstraction,
private platformUtilsService: PlatformUtilsService,
private toastService: ToastService,
private router: Router,
) {
this.clientType = this.platformUtilsService.getClientType();
}
async ngOnInit(): Promise<void> {
const email = (await firstValueFrom(this.loginEmailService.loginEmail$)) ?? "";
this.formGroup.controls.email.setValue(email);
}
submit = async () => {
const isEmailValid = this.validateEmailOrShowToast(this.email);
if (!isEmailValid) {
return;
}
await this.apiService.postPasswordHint(new PasswordHintRequest(this.email));
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t("masterPassSent"),
});
await this.router.navigate(["login"]);
};
protected async cancel() {
this.loginEmailService.setLoginEmail(this.email);
await this.router.navigate(["login"]);
}
private validateEmailOrShowToast(email: string): boolean {
// If email is null or empty, show error toast and return false
if (email == null || email === "") {
this.toastService.showToast({
variant: "error",
title: this.i18nService.t("errorOccurred"),
message: this.i18nService.t("emailRequired"),
});
return false;
}
// If not a valid email format, show error toast and return false
if (email.indexOf("@") === -1) {
this.toastService.showToast({
variant: "error",
title: this.i18nService.t("errorOccurred"),
message: this.i18nService.t("invalidEmail"),
});
return false;
}
return true; // email is valid
}
}

View File

@@ -23,6 +23,9 @@ export class DefaultRegistrationFinishService implements RegistrationFinishServi
email: string,
passwordInputResult: PasswordInputResult,
emailVerificationToken?: string,
orgSponsoredFreeFamilyPlanToken?: string,
acceptEmergencyAccessInviteToken?: string,
emergencyAccessId?: string,
): Promise<string> {
const [newUserKey, newEncUserKey] = await this.cryptoService.makeUserKey(
passwordInputResult.masterKey,
@@ -35,10 +38,13 @@ export class DefaultRegistrationFinishService implements RegistrationFinishServi
const registerRequest = await this.buildRegisterRequest(
email,
emailVerificationToken,
passwordInputResult,
newEncUserKey.encryptedString,
userAsymmetricKeys,
emailVerificationToken,
orgSponsoredFreeFamilyPlanToken,
acceptEmergencyAccessInviteToken,
emergencyAccessId,
);
const capchaBypassToken = await this.accountApiService.registerFinish(registerRequest);
@@ -48,19 +54,21 @@ export class DefaultRegistrationFinishService implements RegistrationFinishServi
protected async buildRegisterRequest(
email: string,
emailVerificationToken: string,
passwordInputResult: PasswordInputResult,
encryptedUserKey: EncryptedString,
userAsymmetricKeys: [string, EncString],
emailVerificationToken?: string,
orgSponsoredFreeFamilyPlanToken?: string, // web only
acceptEmergencyAccessInviteToken?: string, // web only
emergencyAccessId?: string, // web only
): Promise<RegisterFinishRequest> {
const userAsymmetricKeysRequest = new KeysRequest(
userAsymmetricKeys[0],
userAsymmetricKeys[1].encryptedString,
);
return new RegisterFinishRequest(
const registerFinishRequest = new RegisterFinishRequest(
email,
emailVerificationToken,
passwordInputResult.masterKeyHash,
passwordInputResult.hint,
encryptedUserKey,
@@ -68,5 +76,11 @@ export class DefaultRegistrationFinishService implements RegistrationFinishServi
passwordInputResult.kdfConfig.kdfType,
passwordInputResult.kdfConfig.iterations,
);
if (emailVerificationToken) {
registerFinishRequest.emailVerificationToken = emailVerificationToken;
}
return registerFinishRequest;
}
}

View File

@@ -33,11 +33,21 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy {
submitting = false;
email: string;
// Note: this token is the email verification token. It is always supplied as a query param, but
// Note: this token is the email verification token. When it is supplied as a query param,
// it either comes from the email verification email or, if email verification is disabled server side
// via global settings, it comes directly from the registration-start component directly.
// It is not provided when the user is coming from another emailed invite (ex: org invite or enterprise
// org sponsored free family plan invite).
emailVerificationToken: string;
// this token is provided when the user is coming from an emailed invite to
// setup a free family plan sponsored by an organization but they don't have an account yet.
orgSponsoredFreeFamilyPlanToken: string;
// this token is provided when the user is coming from an emailed invite to accept an emergency access invite
acceptEmergencyAccessInviteToken: string;
emergencyAccessId: string;
masterPasswordPolicyOptions: MasterPasswordPolicyOptions | null = null;
constructor(
@@ -69,6 +79,15 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy {
if (qParams.token != null) {
this.emailVerificationToken = qParams.token;
}
if (qParams.orgSponsoredFreeFamilyPlanToken != null) {
this.orgSponsoredFreeFamilyPlanToken = qParams.orgSponsoredFreeFamilyPlanToken;
}
if (qParams.acceptEmergencyAccessInviteToken != null && qParams.emergencyAccessId) {
this.acceptEmergencyAccessInviteToken = qParams.acceptEmergencyAccessInviteToken;
this.emergencyAccessId = qParams.emergencyAccessId;
}
}),
switchMap((qParams: Params) => {
if (
@@ -100,6 +119,9 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy {
this.email,
passwordInputResult,
this.emailVerificationToken,
this.orgSponsoredFreeFamilyPlanToken,
this.acceptEmergencyAccessInviteToken,
this.emergencyAccessId,
);
} catch (e) {
this.validationService.showError(e);

View File

@@ -14,12 +14,18 @@ export abstract class RegistrationFinishService {
*
* @param email The email address of the user.
* @param passwordInputResult The password input result.
* @param emailVerificationToken The optional email verification token. Not present in org invite scenarios.
* @param emailVerificationToken The optional email verification token. Not present in emailed invite scenarios (ex: org invite).
* @param orgSponsoredFreeFamilyPlanToken The optional org sponsored free family plan token.
* @param acceptEmergencyAccessInviteToken The optional accept emergency access invite token.
* @param emergencyAccessId The optional emergency access id which is required to validate the emergency access invite token.
* Returns a promise which resolves to the captcha bypass token string upon a successful account creation.
*/
abstract finishRegistration(
email: string,
passwordInputResult: PasswordInputResult,
emailVerificationToken?: string,
orgSponsoredFreeFamilyPlanToken?: string,
acceptEmergencyAccessInviteToken?: string,
emergencyAccessId?: string,
): Promise<string>;
}