update
This commit is contained in:
parent
2c56b3ef2a
commit
4809bc6478
|
@ -29,338 +29,13 @@
|
|||
</header>
|
||||
|
||||
<!--Testing cpmponent-->
|
||||
<!-- <div class="col-12">
|
||||
<div class="row justify-content-md-center mt-5">
|
||||
<div class="col-4">
|
||||
<div class="card d-block">
|
||||
<div class="card-body">
|
||||
<app-register-form></app-register-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" class="container" ngNativeValidate>
|
||||
<div class="row">
|
||||
<div class="col-7" *ngIf="layout">
|
||||
<div class="mt-5">
|
||||
<!-- Default Body -->
|
||||
<div
|
||||
*ngIf="
|
||||
layout === 'teams' ||
|
||||
layout === 'enterprise' ||
|
||||
layout === 'enterprise1' ||
|
||||
layout === 'default'
|
||||
"
|
||||
>
|
||||
<h1>The Bitwarden Password Manager</h1>
|
||||
<h2>
|
||||
Trusted by millions of individuals, teams, and organizations worldwide for secure
|
||||
password storage and sharing.
|
||||
</h2>
|
||||
<p>Store logins, secure notes, and more</p>
|
||||
<p>Collaborate and share securely</p>
|
||||
<p>Access anywhere on any device</p>
|
||||
<p>Create your account to get started</p>
|
||||
</div>
|
||||
|
||||
<!-- Teams & Enterprise Body -->
|
||||
<div *ngIf="layout === 'teams1' || layout === 'teams2' || layout === 'enterprise2'">
|
||||
<h1>
|
||||
Start Your <span *ngIf="layout === 'teams1' || layout === 'teams1'">Teams<br /></span
|
||||
><span *ngIf="layout === 'enterprise2'">Enterprise</span> Free Trial Now
|
||||
</h1>
|
||||
<h2>
|
||||
Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure
|
||||
password storage and sharing.
|
||||
</h2>
|
||||
<p>Collaborate and share securely</p>
|
||||
<p>Deploy and manage quickly and easily</p>
|
||||
<p>Access anywhere on any device</p>
|
||||
<p>Create your account to get started</p>
|
||||
</div>
|
||||
|
||||
<!-- CNET Campaign Teams & Enterprise Body -->
|
||||
<div *ngIf="layout === 'cnetcmpgnteams' || layout === 'cnetcmpgnent'">
|
||||
<h1>
|
||||
Start Your <span *ngIf="layout === 'cnetcmpgnteams'">Teams<br /></span
|
||||
><span *ngIf="layout === 'cnetcmpgnent'">Enterprise</span> Free Trial Now
|
||||
</h1>
|
||||
<h2>
|
||||
Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure
|
||||
password storage and sharing.
|
||||
</h2>
|
||||
<p>Collaborate and share securely</p>
|
||||
<p>Deploy and manage quickly and easily</p>
|
||||
<p>Access anywhere on any device</p>
|
||||
<p>Create your account to get started</p>
|
||||
</div>
|
||||
|
||||
<!-- CNET Campaign Premium Body -->
|
||||
<div *ngIf="layout === 'cnetcmpgnind'">
|
||||
<h1>Start Your Premium Account Now</h1>
|
||||
<h2>
|
||||
Millions of individuals, teams, and organizations worldwide trust Bitwarden for secure
|
||||
password storage and sharing.
|
||||
</h2>
|
||||
<p>Store logins, secure notes, and more</p>
|
||||
<p>Secure your account with advanced two-step login</p>
|
||||
<p>Access anywhere on any device</p>
|
||||
<p>Create your account to get started</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div [ngClass]="{ 'col-5': layout, 'col-12': !layout }">
|
||||
<div class="row justify-content-md-center mt-5">
|
||||
<div [ngClass]="{ 'col-5': !layout, 'col-12': layout }">
|
||||
<h1 class="lead text-center mb-4" *ngIf="!layout">{{ "createAccount" | i18n }}</h1>
|
||||
<div class="card d-block">
|
||||
<div class="card-body">
|
||||
<app-callout
|
||||
title="{{ 'createOrganizationStep1' | i18n }}"
|
||||
type="info"
|
||||
icon="bwi bwi-thumb-tack"
|
||||
*ngIf="showCreateOrgMessage"
|
||||
>
|
||||
{{ "createOrganizationCreatePersonalAccount" | i18n }}
|
||||
</app-callout>
|
||||
<div class="form-group">
|
||||
<label for="email">{{ "emailAddress" | i18n }}</label>
|
||||
<input
|
||||
id="email"
|
||||
class="form-control"
|
||||
type="text"
|
||||
name="Email"
|
||||
[(ngModel)]="email"
|
||||
required
|
||||
[appAutofocus]="email === ''"
|
||||
inputmode="email"
|
||||
appInputVerbatim="false"
|
||||
/>
|
||||
<small class="form-text text-muted">{{ "emailAddressDesc" | i18n }}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="name">{{ "yourName" | i18n }}</label>
|
||||
<input
|
||||
id="name"
|
||||
class="form-control"
|
||||
type="text"
|
||||
name="Name"
|
||||
[(ngModel)]="name"
|
||||
[appAutofocus]="email !== ''"
|
||||
/>
|
||||
<small class="form-text text-muted">{{ "yourNameDesc" | i18n }}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<app-callout
|
||||
type="info"
|
||||
[enforcedPolicyOptions]="enforcedPolicyOptions"
|
||||
*ngIf="enforcedPolicyOptions"
|
||||
>
|
||||
</app-callout>
|
||||
<label for="masterPassword">{{ "masterPass" | i18n }}</label>
|
||||
<div class="d-flex">
|
||||
<div class="w-100">
|
||||
<input
|
||||
id="masterPassword"
|
||||
type="{{ showPassword ? 'text' : 'password' }}"
|
||||
name="MasterPassword"
|
||||
class="text-monospace form-control mb-1"
|
||||
[(ngModel)]="masterPassword"
|
||||
(input)="updatePasswordStrength()"
|
||||
required
|
||||
appInputVerbatim
|
||||
/>
|
||||
<app-password-strength [score]="masterPasswordScore" [showText]="true">
|
||||
</app-password-strength>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
class="ml-1 btn btn-link"
|
||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||
(click)="togglePassword(false)"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-lg"
|
||||
aria-hidden="true"
|
||||
[ngClass]="{
|
||||
'bwi-eye': !showPassword,
|
||||
'bwi-eye-slash': showPassword
|
||||
}"
|
||||
></i>
|
||||
</button>
|
||||
<div class="progress-bar invisible"></div>
|
||||
</div>
|
||||
</div>
|
||||
<small class="form-text text-muted">{{ "masterPassDesc" | i18n }}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="masterPasswordRetype">{{ "reTypeMasterPass" | i18n }}</label>
|
||||
<div class="d-flex">
|
||||
<input
|
||||
id="masterPasswordRetype"
|
||||
type="{{ showPassword ? 'text' : 'password' }}"
|
||||
name="MasterPasswordRetype"
|
||||
class="text-monospace form-control"
|
||||
[(ngModel)]="confirmMasterPassword"
|
||||
required
|
||||
appInputVerbatim
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="ml-1 btn btn-link"
|
||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
||||
(click)="togglePassword(true)"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-lg"
|
||||
aria-hidden="true"
|
||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
||||
></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="hint">{{ "masterPassHint" | i18n }}</label>
|
||||
<input
|
||||
id="hint"
|
||||
class="form-control"
|
||||
type="text"
|
||||
name="Hint"
|
||||
[(ngModel)]="hint"
|
||||
/>
|
||||
<small class="form-text text-muted">{{ "masterPassHintDesc" | i18n }}</small>
|
||||
</div>
|
||||
<div [hidden]="!showCaptcha()">
|
||||
<iframe id="hcaptcha_iframe" height="80"></iframe>
|
||||
</div>
|
||||
<div class="form-group" *ngIf="showTerms">
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
id="acceptPolicies"
|
||||
[(ngModel)]="acceptPolicies"
|
||||
name="AcceptPolicies"
|
||||
/>
|
||||
<label class="form-check-label small text-muted" for="acceptPolicies">
|
||||
{{ "acceptPolicies" | i18n }}<br />
|
||||
<a href="https://bitwarden.com/terms/" target="_blank" rel="noopener">{{
|
||||
"termsOfService" | i18n
|
||||
}}</a
|
||||
>,
|
||||
<a href="https://bitwarden.com/privacy/" target="_blank" rel="noopener">{{
|
||||
"privacyPolicy" | i18n
|
||||
}}</a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="d-flex mb-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary btn-block btn-submit"
|
||||
[disabled]="form.loading"
|
||||
>
|
||||
<span>{{ "submit" | i18n }}</span>
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-7 d-flex align-items-center">
|
||||
<div
|
||||
*ngIf="
|
||||
layout === 'cnetcmpgnent' || layout === 'cnetcmpgnteams' || layout === 'cnetcmpgnind'
|
||||
"
|
||||
>
|
||||
<figure>
|
||||
<figcaption>
|
||||
<cite>
|
||||
<img
|
||||
src="../../images/register-layout/cnet-logo.svg"
|
||||
class="w-25 d-block mx-auto"
|
||||
alt="cnet logo"
|
||||
/>
|
||||
</cite>
|
||||
</figcaption>
|
||||
<blockquote class="mx-auto text-center px-4">
|
||||
"No more excuses; start using Bitwarden today. The identity you save could be your
|
||||
own. The money definitely will be."
|
||||
</blockquote>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div
|
||||
*ngIf="
|
||||
layout === 'teams' ||
|
||||
layout === 'teams1' ||
|
||||
layout === 'teams2' ||
|
||||
layout === 'enterprise' ||
|
||||
layout === 'enterprise1' ||
|
||||
layout === 'enterprise2' ||
|
||||
layout === 'default'
|
||||
"
|
||||
>
|
||||
<figure>
|
||||
<figcaption>
|
||||
<cite>
|
||||
<img
|
||||
src="../../images/register-layout/forbes-logo.svg"
|
||||
class="w-25 d-block mx-auto"
|
||||
alt="Forbes Logo"
|
||||
/>
|
||||
</cite>
|
||||
</figcaption>
|
||||
<blockquote class="mx-auto text-center px-4">
|
||||
“Bitwarden boasts the backing of some of the world's best security experts and an
|
||||
attractive, easy-to-use interface”
|
||||
</blockquote>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="
|
||||
layout === 'cnetcmpgnent' || layout === 'cnetcmpgnteams' || layout === 'cnetcmpgnind'
|
||||
"
|
||||
class="col-5 d-flex align-items-center justify-content-center"
|
||||
>
|
||||
<img
|
||||
src="../../images/register-layout/usnews-360-badge.svg"
|
||||
class="w-50 d-block"
|
||||
alt="US News 360 Reviews Best Password Manager"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="
|
||||
layout === 'teams' ||
|
||||
layout === 'teams1' ||
|
||||
layout === 'teams2' ||
|
||||
layout === 'enterprise' ||
|
||||
layout === 'enterprise1' ||
|
||||
layout === 'enterprise2' ||
|
||||
layout === 'default'
|
||||
"
|
||||
class="col-5 d-flex align-items-center justify-content-center"
|
||||
>
|
||||
<img
|
||||
src="../../images/register-layout/usnews-360-badge.svg"
|
||||
class="w-50 d-block"
|
||||
alt="US News 360 Reviews Best Password Manager"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Component } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
|
@ -32,6 +33,7 @@ export class RegisterComponent extends BaseRegisterComponent {
|
|||
private policies: Policy[];
|
||||
|
||||
constructor(
|
||||
formBuilder: FormBuilder,
|
||||
authService: AuthService,
|
||||
router: Router,
|
||||
i18nService: I18nService,
|
||||
|
@ -47,6 +49,7 @@ export class RegisterComponent extends BaseRegisterComponent {
|
|||
private routerService: RouterService
|
||||
) {
|
||||
super(
|
||||
formBuilder,
|
||||
authService,
|
||||
router,
|
||||
i18nService,
|
||||
|
|
|
@ -161,7 +161,7 @@ import { FolderAddEditComponent } from "../vault/folder-add-edit.component";
|
|||
import { ShareComponent } from "../vault/share.component";
|
||||
|
||||
import { PipesModule } from "./pipes/pipes.module";
|
||||
import { RegisterFormModule , RegisterFormModule, RegisterFormModule } from "./register-form/register-form.module";
|
||||
import { RegisterFormModule } from "./register-form/register-form.module";
|
||||
import { SharedModule } from "./shared.module";
|
||||
import { VaultFilterModule } from "./vault-filter/vault-filter.module";
|
||||
import { OrganizationBadgeModule } from "./vault/modules/organization-badge/organization-badge.module";
|
||||
|
|
|
@ -3,43 +3,46 @@
|
|||
(ngSubmit)="submit()"
|
||||
[appApiAction]="formPromise"
|
||||
class="tw-container tw-mx-auto"
|
||||
[formGroup]="formData"
|
||||
[formGroup]="formGroup"
|
||||
>
|
||||
<div class="">
|
||||
<!--Email-->
|
||||
<div>
|
||||
<div class="tw-mb-3">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "emailAddress" | i18n }}</bit-label>
|
||||
<input bitInput type="email" formControlName="email" />
|
||||
<bit-hint class="tw-text-sm">{{ "emailAddressDesc" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
<small class="tw-mb-2 tw-text-grey-500">{{ "emailAddressDesc" | i18n }}</small>
|
||||
</div>
|
||||
|
||||
<div class="tw-mb-3">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "name" | i18n }}</bit-label>
|
||||
<input bitInput type="text" formControlName="name" />
|
||||
<bit-hint class="tw-text-sm">{{ "yourNameDesc" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
<small class="tw-mb-2 tw-text-grey-500">{{ "yourNameDesc" | i18n }}</small>
|
||||
</div>
|
||||
|
||||
<div class="tw-mb-3">
|
||||
<!-- <app-callout
|
||||
<app-callout
|
||||
type="info"
|
||||
[enforcedPolicyOptions]="enforcedPolicyOptions"
|
||||
*ngIf="enforcedPolicyOptions"
|
||||
>
|
||||
</app-callout> -->
|
||||
</app-callout>
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "masterPass" | i18n }}</bit-label>
|
||||
|
||||
<div class="tw-w-full">
|
||||
<input
|
||||
#masterPassword
|
||||
class="mb-2"
|
||||
bitInput
|
||||
(input)="updatePasswordStrength()"
|
||||
type="{{ showPassword ? 'text' : 'password' }}"
|
||||
formControlName="masterPassword"
|
||||
/>
|
||||
<app-password-strength [score]="masterPasswordScore" [showText]="true">
|
||||
</app-password-strength>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
|
@ -57,15 +60,18 @@
|
|||
}"
|
||||
></i>
|
||||
</button>
|
||||
<bit-hint class="tw-text-sm">
|
||||
<span class="tw-font-semibold">Important:</span>
|
||||
{{ "masterPassImportant" | i18n }}</bit-hint
|
||||
>
|
||||
</bit-form-field>
|
||||
|
||||
<small class="tw-text-grey-500">{{ "masterPassDesc" | i18n }}</small>
|
||||
</div>
|
||||
|
||||
<div class="tw-mb-3">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "reTypeMasterPass" | i18n }}</bit-label>
|
||||
<input
|
||||
#masterPasswordRetype
|
||||
bitInput
|
||||
type="{{ showPassword ? 'text' : 'password' }}"
|
||||
formControlName="confirmMasterPassword"
|
||||
|
@ -91,8 +97,8 @@
|
|||
<bit-form-field>
|
||||
<bit-label>{{ "masterPassHint" | i18n }}</bit-label>
|
||||
<input bitInput type="text" formControlName="hint" />
|
||||
<bit-hint class="tw-tracking-tight tw-text-sm">{{ "masterPassHintDesc" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
<small class="tw-text-grey-500">{{ "masterPassHintDesc" | i18n }}</small>
|
||||
</div>
|
||||
|
||||
<div [hidden]="!showCaptcha()">
|
||||
|
@ -100,7 +106,7 @@
|
|||
</div>
|
||||
|
||||
<div class="tw-flex tw-items-start tw-mb-3" *ngIf="showTerms">
|
||||
<div class="tw-flex tw-items-center tw-h-5">
|
||||
<div class="tw-flex tw-items-center tw-h-6">
|
||||
<input
|
||||
class="tw-w-4 tw-rounded tw-border tw-border-gray-300"
|
||||
bitInput
|
||||
|
@ -108,16 +114,16 @@
|
|||
formControlName="acceptPolicies"
|
||||
/>
|
||||
</div>
|
||||
<bit-label
|
||||
>{{ "acceptPolicies" | i18n }}<br />
|
||||
<bit-label class="ml-2">
|
||||
{{ "acceptPolicies" | i18n }}<br />
|
||||
<a href="https://bitwarden.com/terms/" target="_blank" rel="noopener">{{
|
||||
"termsOfService" | i18n
|
||||
}}</a
|
||||
>,
|
||||
<a href="https://bitwarden.com/privacy/" target="_blank" rel="noopener">{{
|
||||
"privacyPolicy" | i18n
|
||||
}}</a></bit-label
|
||||
>
|
||||
}}</a>
|
||||
</bit-label>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
@ -128,6 +134,7 @@
|
|||
type="submit"
|
||||
bitButton
|
||||
buttonType="primary"
|
||||
class="btn-submit"
|
||||
[disabled]="form.loading"
|
||||
>
|
||||
<span>{{ "createAccount" | i18n }}</span>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Component, Input } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Component, ElementRef, Input, OnInit, ViewChild } from "@angular/core";
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component";
|
||||
import { CaptchaProtectedComponent } from "@bitwarden/angular/components/captchaProtected.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
|
@ -14,10 +14,13 @@ import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwo
|
|||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
import { PolicyService } from "@bitwarden/common/abstractions/policy.service";
|
||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||
import { DEFAULT_KDF_ITERATIONS, DEFAULT_KDF_TYPE } from "@bitwarden/common/enums/kdfType";
|
||||
import { PolicyData } from "@bitwarden/common/models/data/policyData";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/models/domain/masterPasswordPolicyOptions";
|
||||
import { Policy } from "@bitwarden/common/models/domain/policy";
|
||||
import { KeysRequest } from "@bitwarden/common/models/request/keysRequest";
|
||||
import { ReferenceEventRequest } from "@bitwarden/common/models/request/referenceEventRequest";
|
||||
import { RegisterRequest } from "@bitwarden/common/models/request/registerRequest";
|
||||
|
||||
import { RouterService } from "src/app/services/router.service";
|
||||
|
||||
|
@ -25,57 +28,52 @@ import { RouterService } from "src/app/services/router.service";
|
|||
selector: "app-register-form",
|
||||
templateUrl: "./register-form.component.html",
|
||||
})
|
||||
export class RegisterFormComponent extends BaseRegisterComponent {
|
||||
export class RegisterFormComponent extends CaptchaProtectedComponent implements OnInit {
|
||||
@ViewChild("masterPassword") masterPasswordRef: ElementRef;
|
||||
@ViewChild("masterPasswordRetype") masterPasswordRetypeRef: ElementRef;
|
||||
|
||||
showTerms = true;
|
||||
showCreateOrgMessage = false;
|
||||
@Input() layout = "";
|
||||
masterPasswordScore: number;
|
||||
showPassword = false;
|
||||
referenceData: ReferenceEventRequest;
|
||||
enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||
formGroup: FormGroup;
|
||||
formPromise: Promise<any>;
|
||||
showErrorSummary = false;
|
||||
|
||||
private policies: Policy[];
|
||||
|
||||
formData = this.formBuilder.group({
|
||||
email: ["", [Validators.required, Validators.email]],
|
||||
name: ["", [Validators.required]],
|
||||
masterPassword: ["", [Validators.required]],
|
||||
confirmMasterPassword: ["", [Validators.required]],
|
||||
hint: [],
|
||||
acceptPolicies: [false, [Validators.requiredTrue]],
|
||||
});
|
||||
protected successRoute = "login";
|
||||
private masterPasswordStrengthTimeout: any;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
authService: AuthService,
|
||||
router: Router,
|
||||
private router: Router,
|
||||
i18nService: I18nService,
|
||||
cryptoService: CryptoService,
|
||||
apiService: ApiService,
|
||||
private cryptoService: CryptoService,
|
||||
private apiService: ApiService,
|
||||
private route: ActivatedRoute,
|
||||
stateService: StateService,
|
||||
private stateService: StateService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
passwordGenerationService: PasswordGenerationService,
|
||||
private passwordGenerationService: PasswordGenerationService,
|
||||
private policyService: PolicyService,
|
||||
environmentService: EnvironmentService,
|
||||
logService: LogService,
|
||||
private logService: LogService,
|
||||
private routerService: RouterService
|
||||
) {
|
||||
super(
|
||||
authService,
|
||||
router,
|
||||
i18nService,
|
||||
cryptoService,
|
||||
apiService,
|
||||
stateService,
|
||||
platformUtilsService,
|
||||
passwordGenerationService,
|
||||
environmentService,
|
||||
logService
|
||||
);
|
||||
super(environmentService, i18nService, platformUtilsService);
|
||||
this.showTerms = !platformUtilsService.isSelfHost();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.createRegisterForm();
|
||||
|
||||
this.route.queryParams.pipe(first()).subscribe((qParams) => {
|
||||
this.referenceData = new ReferenceEventRequest();
|
||||
if (qParams.email != null && qParams.email.indexOf("@") > -1) {
|
||||
this.email = qParams.email;
|
||||
this.formGroup.get("email")?.setValue(qParams.email);
|
||||
}
|
||||
if (qParams.premium != null) {
|
||||
this.routerService.setPreviousUrl("/settings/premium");
|
||||
|
@ -87,9 +85,7 @@ export class RegisterFormComponent extends BaseRegisterComponent {
|
|||
});
|
||||
this.routerService.setPreviousUrl(route.toString());
|
||||
}
|
||||
if (qParams.layout != null) {
|
||||
this.layout = this.referenceData.layout = qParams.layout;
|
||||
}
|
||||
|
||||
if (qParams.reference != null) {
|
||||
this.referenceData.id = qParams.reference;
|
||||
} else {
|
||||
|
@ -135,15 +131,68 @@ export class RegisterFormComponent extends BaseRegisterComponent {
|
|||
);
|
||||
}
|
||||
|
||||
await super.ngOnInit();
|
||||
this.setupCaptcha();
|
||||
}
|
||||
|
||||
get masterPasswordScoreWidth() {
|
||||
return this.masterPasswordScore == null ? 0 : (this.masterPasswordScore + 1) * 20;
|
||||
}
|
||||
|
||||
get masterPasswordScoreColor() {
|
||||
switch (this.masterPasswordScore) {
|
||||
case 4:
|
||||
return "success";
|
||||
case 3:
|
||||
return "primary";
|
||||
case 2:
|
||||
return "warning";
|
||||
default:
|
||||
return "danger";
|
||||
}
|
||||
}
|
||||
|
||||
get masterPasswordScoreText() {
|
||||
switch (this.masterPasswordScore) {
|
||||
case 4:
|
||||
return this.i18nService.t("strong");
|
||||
case 3:
|
||||
return this.i18nService.t("good");
|
||||
case 2:
|
||||
return this.i18nService.t("weak");
|
||||
default:
|
||||
return this.masterPasswordScore != null ? this.i18nService.t("weak") : null;
|
||||
}
|
||||
}
|
||||
|
||||
async submit() {
|
||||
let email = this.formGroup.get("email")?.value;
|
||||
let name = this.formGroup.get("name")?.value;
|
||||
const masterPassword = this.formGroup.get("masterPassword")?.value;
|
||||
const confirmMasterPassword = this.formGroup.get("confirmMasterPassword")?.value;
|
||||
const hint = this.formGroup.get("hint")?.value;
|
||||
const acceptPolicies = this.formGroup.get("acceptPolicies")?.value;
|
||||
|
||||
// if (!acceptPolicies && this.showTerms) {
|
||||
// this.platformUtilsService.showToast(
|
||||
// "error",
|
||||
// this.i18nService.t("errorOccurred"),
|
||||
// this.i18nService.t("acceptPoliciesError")
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
this.formGroup.markAllAsTouched();
|
||||
this.showErrorSummary = true;
|
||||
|
||||
if (!this.formGroup.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.enforcedPolicyOptions != null &&
|
||||
!this.policyService.evaluateMasterPassword(
|
||||
this.masterPasswordScore,
|
||||
this.masterPassword,
|
||||
masterPassword,
|
||||
this.enforcedPolicyOptions
|
||||
)
|
||||
) {
|
||||
|
@ -155,6 +204,138 @@ export class RegisterFormComponent extends BaseRegisterComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
await super.submit();
|
||||
console.log("Here::", acceptPolicies, this.showTerms);
|
||||
|
||||
if (masterPassword !== confirmMasterPassword) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("masterPassDoesntMatch")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const strengthResult = this.passwordGenerationService.passwordStrength(
|
||||
masterPassword,
|
||||
this.getPasswordStrengthUserInput()
|
||||
);
|
||||
if (strengthResult != null && strengthResult.score < 3) {
|
||||
const result = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t("weakMasterPasswordDesc"),
|
||||
this.i18nService.t("weakMasterPassword"),
|
||||
this.i18nService.t("yes"),
|
||||
this.i18nService.t("no"),
|
||||
"warning"
|
||||
);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (hint === masterPassword) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("hintEqualsPassword")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
name = name === "" ? null : name;
|
||||
email = email.trim().toLowerCase();
|
||||
const kdf = DEFAULT_KDF_TYPE;
|
||||
const kdfIterations = DEFAULT_KDF_ITERATIONS;
|
||||
const key = await this.cryptoService.makeKey(masterPassword, email, kdf, kdfIterations);
|
||||
const encKey = await this.cryptoService.makeEncKey(key);
|
||||
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
|
||||
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
|
||||
const request = new RegisterRequest(
|
||||
email,
|
||||
name,
|
||||
hashedPassword,
|
||||
hint,
|
||||
encKey[1].encryptedString,
|
||||
kdf,
|
||||
kdfIterations,
|
||||
this.referenceData,
|
||||
this.captchaToken
|
||||
);
|
||||
request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
|
||||
const orgInvite = await this.stateService.getOrganizationInvitation();
|
||||
if (orgInvite != null && orgInvite.token != null && orgInvite.organizationUserId != null) {
|
||||
request.token = orgInvite.token;
|
||||
request.organizationUserId = orgInvite.organizationUserId;
|
||||
}
|
||||
|
||||
try {
|
||||
this.formPromise = this.apiService.postRegister(request);
|
||||
try {
|
||||
await this.formPromise;
|
||||
} catch (e) {
|
||||
if (this.handleCaptchaRequired(e)) {
|
||||
return;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("newAccountCreated"));
|
||||
this.router.navigate([this.successRoute], { queryParams: { email: email } });
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
togglePassword(confirmField: boolean) {
|
||||
this.showPassword = !this.showPassword;
|
||||
confirmField
|
||||
? this.masterPasswordRetypeRef.nativeElement.focus()
|
||||
: this.masterPasswordRef.nativeElement.focus();
|
||||
// document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
|
||||
}
|
||||
|
||||
updatePasswordStrength() {
|
||||
const masterPassword = this.formGroup.get("masterPassword")?.value;
|
||||
|
||||
if (this.masterPasswordStrengthTimeout != null) {
|
||||
clearTimeout(this.masterPasswordStrengthTimeout);
|
||||
}
|
||||
this.masterPasswordStrengthTimeout = setTimeout(() => {
|
||||
const strengthResult = this.passwordGenerationService.passwordStrength(
|
||||
masterPassword,
|
||||
this.getPasswordStrengthUserInput()
|
||||
);
|
||||
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
|
||||
}, 300);
|
||||
}
|
||||
|
||||
private getPasswordStrengthUserInput() {
|
||||
let userInput: string[] = [];
|
||||
const email = this.formGroup.get("email")?.value;
|
||||
const name = this.formGroup.get("name").value;
|
||||
const atPosition = email.indexOf("@");
|
||||
if (atPosition > -1) {
|
||||
userInput = userInput.concat(
|
||||
email
|
||||
.substr(0, atPosition)
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.split(/[^A-Za-z0-9]/)
|
||||
);
|
||||
}
|
||||
if (name != null && name !== "") {
|
||||
userInput = userInput.concat(name.trim().toLowerCase().split(" "));
|
||||
}
|
||||
return userInput;
|
||||
}
|
||||
|
||||
private createRegisterForm() {
|
||||
this.formGroup = this.formBuilder.group({
|
||||
email: ["", [Validators.required, Validators.email]],
|
||||
name: [""],
|
||||
masterPassword: ["", [Validators.required]],
|
||||
confirmMasterPassword: ["", [Validators.required]],
|
||||
hint: [],
|
||||
acceptPolicies: [false, [Validators.requiredTrue]],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -593,6 +593,9 @@
|
|||
"masterPassDesc": {
|
||||
"message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it."
|
||||
},
|
||||
"masterPassImportant": {
|
||||
"message": "Master passwords cannot be recovered if you forget it!"
|
||||
},
|
||||
"masterPassHintDesc": {
|
||||
"message": "A master password hint can help you remember your password if you forget it."
|
||||
},
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Directive, OnInit } from "@angular/core";
|
||||
import { Directive, ElementRef, OnInit, ViewChild } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
|
@ -19,6 +20,8 @@ import { CaptchaProtectedComponent } from "./captchaProtected.component";
|
|||
|
||||
@Directive()
|
||||
export class RegisterComponent extends CaptchaProtectedComponent implements OnInit {
|
||||
@ViewChild("masterPassword") masterPasswordRef: ElementRef;
|
||||
@ViewChild("masterPasswordRetype") masterPasswordRetypeRef: ElementRef;
|
||||
name = "";
|
||||
email = "";
|
||||
masterPassword = "";
|
||||
|
@ -31,10 +34,20 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
showTerms = true;
|
||||
acceptPolicies = false;
|
||||
|
||||
formGroup = this.formBuilder.group({
|
||||
email: ["", [Validators.required, Validators.email]],
|
||||
name: [""],
|
||||
masterPassword: ["", [Validators.required]],
|
||||
confirmMasterPassword: ["", [Validators.required]],
|
||||
hint: [],
|
||||
acceptPolicies: [false, [Validators.requiredTrue]],
|
||||
});
|
||||
|
||||
protected successRoute = "login";
|
||||
private masterPasswordStrengthTimeout: any;
|
||||
|
||||
constructor(
|
||||
protected formBuilder: FormBuilder,
|
||||
protected authService: AuthService,
|
||||
protected router: Router,
|
||||
i18nService: I18nService,
|
||||
|
@ -85,7 +98,20 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
}
|
||||
|
||||
async submit() {
|
||||
if (!this.acceptPolicies && this.showTerms) {
|
||||
let email = this.formGroup.get("email")?.value;
|
||||
let name = this.formGroup.get("name")?.value;
|
||||
const masterPassword = this.formGroup.get("masterPassword")?.value;
|
||||
const confirmMasterPassword = this.formGroup.get("confirmMasterPassword")?.value;
|
||||
const hint = this.formGroup.get("hint")?.value;
|
||||
const acceptPolicies = this.formGroup.get("acceptPolicies")?.value;
|
||||
|
||||
this.formGroup.markAllAsTouched();
|
||||
|
||||
if (!this.formGroup.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!acceptPolicies && this.showTerms) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
|
@ -94,7 +120,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.email == null || this.email === "") {
|
||||
if (email == null || email === "") {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
|
@ -102,7 +128,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (this.email.indexOf("@") === -1) {
|
||||
if (email.indexOf("@") === -1) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
|
@ -110,7 +136,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (this.masterPassword == null || this.masterPassword === "") {
|
||||
if (masterPassword == null || masterPassword === "") {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
|
@ -118,7 +144,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (this.masterPassword.length < 8) {
|
||||
if (masterPassword.length < 8) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
|
@ -126,7 +152,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (this.masterPassword !== this.confirmMasterPassword) {
|
||||
if (masterPassword !== confirmMasterPassword) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
|
@ -136,7 +162,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
}
|
||||
|
||||
const strengthResult = this.passwordGenerationService.passwordStrength(
|
||||
this.masterPassword,
|
||||
masterPassword,
|
||||
this.getPasswordStrengthUserInput()
|
||||
);
|
||||
if (strengthResult != null && strengthResult.score < 3) {
|
||||
|
@ -152,7 +178,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
}
|
||||
}
|
||||
|
||||
if (this.hint === this.masterPassword) {
|
||||
if (hint === masterPassword) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
|
@ -161,24 +187,19 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
return;
|
||||
}
|
||||
|
||||
this.name = this.name === "" ? null : this.name;
|
||||
this.email = this.email.trim().toLowerCase();
|
||||
name = name === "" ? null : name;
|
||||
email = email.trim().toLowerCase();
|
||||
const kdf = DEFAULT_KDF_TYPE;
|
||||
const kdfIterations = DEFAULT_KDF_ITERATIONS;
|
||||
const key = await this.cryptoService.makeKey(
|
||||
this.masterPassword,
|
||||
this.email,
|
||||
kdf,
|
||||
kdfIterations
|
||||
);
|
||||
const key = await this.cryptoService.makeKey(masterPassword, email, kdf, kdfIterations);
|
||||
const encKey = await this.cryptoService.makeEncKey(key);
|
||||
const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key);
|
||||
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
|
||||
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
|
||||
const request = new RegisterRequest(
|
||||
this.email,
|
||||
this.name,
|
||||
email,
|
||||
name,
|
||||
hashedPassword,
|
||||
this.hint,
|
||||
hint,
|
||||
encKey[1].encryptedString,
|
||||
kdf,
|
||||
kdfIterations,
|
||||
|
@ -204,7 +225,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
}
|
||||
}
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("newAccountCreated"));
|
||||
this.router.navigate([this.successRoute], { queryParams: { email: this.email } });
|
||||
this.router.navigate([this.successRoute], { queryParams: { email: email } });
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
@ -212,18 +233,21 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
|
||||
togglePassword(confirmField: boolean) {
|
||||
this.showPassword = !this.showPassword;
|
||||
console.log("Here::", document.getElementById("masterPasswordRetype"));
|
||||
console.log("Here2::", document.getElementById("masterPassword"));
|
||||
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
|
||||
confirmField
|
||||
? this.masterPasswordRetypeRef.nativeElement.focus()
|
||||
: this.masterPasswordRef.nativeElement.focus();
|
||||
// document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
|
||||
}
|
||||
|
||||
updatePasswordStrength() {
|
||||
const masterPassword = this.formGroup.get("masterPassword")?.value;
|
||||
|
||||
if (this.masterPasswordStrengthTimeout != null) {
|
||||
clearTimeout(this.masterPasswordStrengthTimeout);
|
||||
}
|
||||
this.masterPasswordStrengthTimeout = setTimeout(() => {
|
||||
const strengthResult = this.passwordGenerationService.passwordStrength(
|
||||
this.masterPassword,
|
||||
masterPassword,
|
||||
this.getPasswordStrengthUserInput()
|
||||
);
|
||||
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
|
||||
|
@ -232,18 +256,20 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||
|
||||
private getPasswordStrengthUserInput() {
|
||||
let userInput: string[] = [];
|
||||
const atPosition = this.email.indexOf("@");
|
||||
const email = this.formGroup.get("email")?.value;
|
||||
const name = this.formGroup.get("name").value;
|
||||
const atPosition = email.indexOf("@");
|
||||
if (atPosition > -1) {
|
||||
userInput = userInput.concat(
|
||||
this.email
|
||||
email
|
||||
.substr(0, atPosition)
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.split(/[^A-Za-z0-9]/)
|
||||
);
|
||||
}
|
||||
if (this.name != null && this.name !== "") {
|
||||
userInput = userInput.concat(this.name.trim().toLowerCase().split(" "));
|
||||
if (name != null && name !== "") {
|
||||
userInput = userInput.concat(name.trim().toLowerCase().split(" "));
|
||||
}
|
||||
return userInput;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue