mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 13:53:34 +00:00
refactor: [PM-17530] remove obsolete registration component
Remove outdated registration components and associated routes to cleanup the codebase and eliminate legacy functionality.
This commit is contained in:
@@ -1,147 +0,0 @@
|
|||||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" [formGroup]="formGroup">
|
|
||||||
<header>
|
|
||||||
<div class="left">
|
|
||||||
<button type="button" routerLink="/home">{{ "cancel" | i18n }}</button>
|
|
||||||
</div>
|
|
||||||
<h1 class="center">
|
|
||||||
<span class="title">{{ "createAccount" | i18n }}</span>
|
|
||||||
</h1>
|
|
||||||
<div class="right">
|
|
||||||
<button type="submit" [disabled]="form.loading">
|
|
||||||
<span [hidden]="form.loading">{{ "submit" | i18n }}</span>
|
|
||||||
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<main tabindex="-1">
|
|
||||||
<div class="box">
|
|
||||||
<div class="box-content">
|
|
||||||
<div class="box-content-row" appBoxRow>
|
|
||||||
<label for="email">{{ "emailAddress" | i18n }}</label>
|
|
||||||
<input id="email" type="email" formControlName="email" appInputVerbatim="false" />
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" appBoxRow>
|
|
||||||
<div class="box-content-row-flex">
|
|
||||||
<div class="row-main">
|
|
||||||
<label for="masterPassword">
|
|
||||||
{{ "masterPass" | i18n }}
|
|
||||||
<strong class="sub-label text-{{ color }}" *ngIf="text">
|
|
||||||
{{ text }}
|
|
||||||
</strong>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="masterPassword"
|
|
||||||
type="{{ showPassword ? 'text' : 'password' }}"
|
|
||||||
aria-describedby="masterPasswordHelp"
|
|
||||||
class="monospaced"
|
|
||||||
formControlName="masterPassword"
|
|
||||||
appInputVerbatim
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="action-buttons">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="row-btn"
|
|
||||||
appStopClick
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
|
||||||
(click)="togglePassword()"
|
|
||||||
[attr.aria-pressed]="showPassword"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="bwi bwi-lg"
|
|
||||||
aria-hidden="true"
|
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
|
||||||
></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<app-password-strength
|
|
||||||
[password]="formGroup.get('masterPassword')?.value"
|
|
||||||
[email]="formGroup.get('email')?.value"
|
|
||||||
[name]="formGroup.get('name')?.value"
|
|
||||||
(passwordStrengthResult)="getStrengthResult($event)"
|
|
||||||
(passwordScoreColor)="getPasswordScoreText($event)"
|
|
||||||
>
|
|
||||||
</app-password-strength>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="masterPasswordHelp" class="box-footer">
|
|
||||||
<b>{{ "important" | i18n }}</b> {{ "masterPasswordHint" | i18n }}
|
|
||||||
{{ characterMinimumMessage }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="box">
|
|
||||||
<div class="box-content">
|
|
||||||
<div class="box-content-row box-content-row-flex" appBoxRow>
|
|
||||||
<div class="row-main">
|
|
||||||
<label for="masterPasswordRetype">{{ "reTypeMasterPass" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="masterPasswordRetype"
|
|
||||||
type="{{ showPassword ? 'text' : 'password' }}"
|
|
||||||
class="monospaced"
|
|
||||||
formControlName="confirmMasterPassword"
|
|
||||||
appInputVerbatim
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="action-buttons">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="row-btn"
|
|
||||||
appStopClick
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
|
||||||
(click)="togglePassword()"
|
|
||||||
[attr.aria-pressed]="showPassword"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="bwi bwi-lg"
|
|
||||||
aria-hidden="true"
|
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
|
||||||
></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" appBoxRow>
|
|
||||||
<label for="hint">{{ "masterPassHint" | i18n }}</label>
|
|
||||||
<input id="hint" type="text" aria-describedby="hintHelp" formControlName="hint" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="hintHelp" class="box-footer">
|
|
||||||
{{ "masterPassHintDesc" | i18n }}
|
|
||||||
</div>
|
|
||||||
<div class="box-content row-top-padding">
|
|
||||||
<div
|
|
||||||
class="box-content-row box-content-row-checkbox box-content-row-checkbox-left box-content-row-word-break"
|
|
||||||
appBoxRow
|
|
||||||
>
|
|
||||||
<input type="checkbox" id="checkForBreaches" formControlName="checkForBreaches" />
|
|
||||||
<label for="checkForBreaches">
|
|
||||||
{{ "checkForBreaches" | i18n }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div [hidden]="!showCaptcha()">
|
|
||||||
<iframe id="hcaptcha_iframe" height="80" sandbox="allow-scripts allow-same-origin"></iframe>
|
|
||||||
</div>
|
|
||||||
<div class="box last" *ngIf="showTerms">
|
|
||||||
<div class="box-content">
|
|
||||||
<div
|
|
||||||
class="box-content-row box-content-row-checkbox box-content-row-checkbox-left box-content-row-word-break"
|
|
||||||
appBoxRow
|
|
||||||
>
|
|
||||||
<input type="checkbox" id="acceptPolicies" formControlName="acceptPolicies" />
|
|
||||||
<label for="acceptPolicies">
|
|
||||||
{{ "acceptPolicies" | i18n }}<br />
|
|
||||||
<a href="https://bitwarden.com/terms/" target="_blank" rel="noreferrer">{{
|
|
||||||
"termsOfService" | i18n
|
|
||||||
}}</a
|
|
||||||
>,
|
|
||||||
<a href="https://bitwarden.com/privacy/" target="_blank" rel="noreferrer">{{
|
|
||||||
"privacyPolicy" | i18n
|
|
||||||
}}</a>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</form>
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Component } from "@angular/core";
|
|
||||||
import { UntypedFormBuilder } from "@angular/forms";
|
|
||||||
import { Router } from "@angular/router";
|
|
||||||
|
|
||||||
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/auth/components/register.component";
|
|
||||||
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
|
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|
||||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
import { DialogService, ToastService } from "@bitwarden/components";
|
|
||||||
import { KeyService } from "@bitwarden/key-management";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-register",
|
|
||||||
templateUrl: "register.component.html",
|
|
||||||
})
|
|
||||||
export class RegisterComponent extends BaseRegisterComponent {
|
|
||||||
color: string;
|
|
||||||
text: string;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
formValidationErrorService: FormValidationErrorsService,
|
|
||||||
formBuilder: UntypedFormBuilder,
|
|
||||||
loginStrategyService: LoginStrategyServiceAbstraction,
|
|
||||||
router: Router,
|
|
||||||
i18nService: I18nService,
|
|
||||||
keyService: KeyService,
|
|
||||||
apiService: ApiService,
|
|
||||||
platformUtilsService: PlatformUtilsService,
|
|
||||||
environmentService: EnvironmentService,
|
|
||||||
logService: LogService,
|
|
||||||
auditService: AuditService,
|
|
||||||
dialogService: DialogService,
|
|
||||||
toastService: ToastService,
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
formValidationErrorService,
|
|
||||||
formBuilder,
|
|
||||||
loginStrategyService,
|
|
||||||
router,
|
|
||||||
i18nService,
|
|
||||||
keyService,
|
|
||||||
apiService,
|
|
||||||
platformUtilsService,
|
|
||||||
environmentService,
|
|
||||||
logService,
|
|
||||||
auditService,
|
|
||||||
dialogService,
|
|
||||||
toastService,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -64,7 +64,6 @@ import { HomeComponent } from "../auth/popup/home.component";
|
|||||||
import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component";
|
import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component";
|
||||||
import { LoginComponentV1 } from "../auth/popup/login-v1.component";
|
import { LoginComponentV1 } from "../auth/popup/login-v1.component";
|
||||||
import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component";
|
import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component";
|
||||||
import { RegisterComponent } from "../auth/popup/register.component";
|
|
||||||
import { RemovePasswordComponent } from "../auth/popup/remove-password.component";
|
import { RemovePasswordComponent } from "../auth/popup/remove-password.component";
|
||||||
import { SetPasswordComponent } from "../auth/popup/set-password.component";
|
import { SetPasswordComponent } from "../auth/popup/set-password.component";
|
||||||
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
|
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
|
||||||
@@ -267,12 +266,6 @@ const routes: Routes = [
|
|||||||
canActivate: [authGuard],
|
canActivate: [authGuard],
|
||||||
data: { elevation: 1 } satisfies RouteDataProperties,
|
data: { elevation: 1 } satisfies RouteDataProperties,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "register",
|
|
||||||
component: RegisterComponent,
|
|
||||||
canActivate: [unauthGuardFn(unauthRouteOverrides)],
|
|
||||||
data: { elevation: 1 } satisfies RouteDataProperties,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "environment",
|
path: "environment",
|
||||||
component: EnvironmentComponent,
|
component: EnvironmentComponent,
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import { HomeComponent } from "../auth/popup/home.component";
|
|||||||
import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component";
|
import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component";
|
||||||
import { LoginComponentV1 } from "../auth/popup/login-v1.component";
|
import { LoginComponentV1 } from "../auth/popup/login-v1.component";
|
||||||
import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component";
|
import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component";
|
||||||
import { RegisterComponent } from "../auth/popup/register.component";
|
|
||||||
import { RemovePasswordComponent } from "../auth/popup/remove-password.component";
|
import { RemovePasswordComponent } from "../auth/popup/remove-password.component";
|
||||||
import { SetPasswordComponent } from "../auth/popup/set-password.component";
|
import { SetPasswordComponent } from "../auth/popup/set-password.component";
|
||||||
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
|
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
|
||||||
@@ -103,7 +102,6 @@ import "../platform/popup/locales";
|
|||||||
LoginViaAuthRequestComponentV1,
|
LoginViaAuthRequestComponentV1,
|
||||||
LoginComponentV1,
|
LoginComponentV1,
|
||||||
LoginDecryptionOptionsComponentV1,
|
LoginDecryptionOptionsComponentV1,
|
||||||
RegisterComponent,
|
|
||||||
SetPasswordComponent,
|
SetPasswordComponent,
|
||||||
SsoComponentV1,
|
SsoComponentV1,
|
||||||
TabsV2Component,
|
TabsV2Component,
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ import { HintComponent } from "../auth/hint.component";
|
|||||||
import { LoginDecryptionOptionsComponentV1 } from "../auth/login/login-decryption-options/login-decryption-options-v1.component";
|
import { LoginDecryptionOptionsComponentV1 } from "../auth/login/login-decryption-options/login-decryption-options-v1.component";
|
||||||
import { LoginComponentV1 } from "../auth/login/login-v1.component";
|
import { LoginComponentV1 } from "../auth/login/login-v1.component";
|
||||||
import { LoginViaAuthRequestComponentV1 } from "../auth/login/login-via-auth-request-v1.component";
|
import { LoginViaAuthRequestComponentV1 } from "../auth/login/login-via-auth-request-v1.component";
|
||||||
import { RegisterComponent } from "../auth/register.component";
|
|
||||||
import { RemovePasswordComponent } from "../auth/remove-password.component";
|
import { RemovePasswordComponent } from "../auth/remove-password.component";
|
||||||
import { SetPasswordComponent } from "../auth/set-password.component";
|
import { SetPasswordComponent } from "../auth/set-password.component";
|
||||||
import { SsoComponentV1 } from "../auth/sso-v1.component";
|
import { SsoComponentV1 } from "../auth/sso-v1.component";
|
||||||
@@ -136,7 +135,6 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
} satisfies RouteDataProperties & AnonLayoutWrapperData,
|
} satisfies RouteDataProperties & AnonLayoutWrapperData,
|
||||||
},
|
},
|
||||||
{ path: "register", component: RegisterComponent },
|
|
||||||
{
|
{
|
||||||
path: "new-device-notice",
|
path: "new-device-notice",
|
||||||
component: AnonLayoutWrapperComponent,
|
component: AnonLayoutWrapperComponent,
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import { DeleteAccountComponent } from "../auth/delete-account.component";
|
|||||||
import { EnvironmentComponent } from "../auth/environment.component";
|
import { EnvironmentComponent } from "../auth/environment.component";
|
||||||
import { HintComponent } from "../auth/hint.component";
|
import { HintComponent } from "../auth/hint.component";
|
||||||
import { LoginModule } from "../auth/login/login.module";
|
import { LoginModule } from "../auth/login/login.module";
|
||||||
import { RegisterComponent } from "../auth/register.component";
|
|
||||||
import { RemovePasswordComponent } from "../auth/remove-password.component";
|
import { RemovePasswordComponent } from "../auth/remove-password.component";
|
||||||
import { SetPasswordComponent } from "../auth/set-password.component";
|
import { SetPasswordComponent } from "../auth/set-password.component";
|
||||||
import { SsoComponentV1 } from "../auth/sso-v1.component";
|
import { SsoComponentV1 } from "../auth/sso-v1.component";
|
||||||
@@ -80,7 +79,6 @@ import { SendComponent } from "./tools/send/send.component";
|
|||||||
NavComponent,
|
NavComponent,
|
||||||
PasswordHistoryComponent,
|
PasswordHistoryComponent,
|
||||||
PremiumComponent,
|
PremiumComponent,
|
||||||
RegisterComponent,
|
|
||||||
RemovePasswordComponent,
|
RemovePasswordComponent,
|
||||||
SearchComponent,
|
SearchComponent,
|
||||||
SendAddEditComponent,
|
SendAddEditComponent,
|
||||||
|
|||||||
@@ -1,150 +0,0 @@
|
|||||||
<form
|
|
||||||
id="register-page"
|
|
||||||
#form
|
|
||||||
(ngSubmit)="submit()"
|
|
||||||
[appApiAction]="formPromise"
|
|
||||||
[formGroup]="formGroup"
|
|
||||||
>
|
|
||||||
<div class="content">
|
|
||||||
<h1>{{ "createAccount" | i18n }}</h1>
|
|
||||||
<div class="box">
|
|
||||||
<div class="box-content">
|
|
||||||
<div class="box-content-row" appBoxRow>
|
|
||||||
<label for="email">{{ "emailAddress" | i18n }}</label>
|
|
||||||
<input id="email" type="email" formControlName="email" appInputVerbatim />
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" appBoxRow>
|
|
||||||
<div class="box-content-row-flex">
|
|
||||||
<div class="row-main">
|
|
||||||
<label for="masterPassword">
|
|
||||||
{{ "masterPass" | i18n }}
|
|
||||||
<strong class="sub-label text-{{ color }}" *ngIf="text">
|
|
||||||
{{ text }}
|
|
||||||
</strong>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="masterPassword"
|
|
||||||
type="{{ showPassword ? 'text' : 'password' }}"
|
|
||||||
class="monospaced"
|
|
||||||
aria-describedby="masterPasswordHelp"
|
|
||||||
formControlName="masterPassword"
|
|
||||||
appInputVerbatim
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="action-buttons">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="row-btn"
|
|
||||||
appStopClick
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
|
||||||
[attr.aria-pressed]="showPassword"
|
|
||||||
(click)="togglePassword()"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="bwi bwi-lg"
|
|
||||||
aria-hidden="true"
|
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
|
||||||
></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<app-password-strength
|
|
||||||
[password]="formGroup.get('masterPassword')?.value"
|
|
||||||
[email]="formGroup.get('email')?.value"
|
|
||||||
[name]="formGroup.get('name')?.value"
|
|
||||||
(passwordStrengthResult)="getStrengthResult($event)"
|
|
||||||
(passwordScoreColor)="getPasswordScoreText($event)"
|
|
||||||
>
|
|
||||||
</app-password-strength>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="masterPasswordHelp" class="box-footer">
|
|
||||||
<b>{{ "important" | i18n }}</b> {{ "masterPasswordHint" | i18n }}
|
|
||||||
{{ characterMinimumMessage }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="box">
|
|
||||||
<div class="box-content">
|
|
||||||
<div class="box-content-row box-content-row-flex" appBoxRow>
|
|
||||||
<div class="row-main">
|
|
||||||
<label for="masterPasswordRetype">{{ "reTypeMasterPass" | i18n }}</label>
|
|
||||||
<input
|
|
||||||
id="masterPasswordRetype"
|
|
||||||
type="{{ showPassword ? 'text' : 'password' }}"
|
|
||||||
class="monospaced"
|
|
||||||
formControlName="confirmMasterPassword"
|
|
||||||
appInputVerbatim
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="action-buttons">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="row-btn"
|
|
||||||
appStopClick
|
|
||||||
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
|
|
||||||
[attr.aria-pressed]="showPassword"
|
|
||||||
(click)="togglePassword()"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="bwi bwi-lg"
|
|
||||||
aria-hidden="true"
|
|
||||||
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
|
|
||||||
></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="box-content-row" appBoxRow>
|
|
||||||
<label for="hint">{{ "masterPassHint" | i18n }}</label>
|
|
||||||
<input id="hint" type="text" aria-describedby="hintHelp" formControlName="hint" />
|
|
||||||
</div>
|
|
||||||
<div class="box last" [hidden]="!showCaptcha()">
|
|
||||||
<div class="box-content">
|
|
||||||
<div class="box-content-row">
|
|
||||||
<iframe
|
|
||||||
id="hcaptcha_iframe"
|
|
||||||
height="80"
|
|
||||||
sandbox="allow-scripts allow-same-origin"
|
|
||||||
></iframe>
|
|
||||||
<button class="btn block" type="button" routerLink="/accessibility-cookie">
|
|
||||||
<i class="bwi bwi-universal-access" aria-hidden="true"></i>
|
|
||||||
{{ "loadAccessibilityCookie" | i18n }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="hintHelp" class="box-footer">
|
|
||||||
{{ "masterPassHintDesc" | i18n }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="box last">
|
|
||||||
<div class="box-footer checkbox">
|
|
||||||
<input type="checkbox" id="checkForBreaches" formControlName="checkForBreaches" />
|
|
||||||
<label for="checkForBreaches">
|
|
||||||
{{ "checkForBreaches" | i18n }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="box-footer checkbox" *ngIf="showTerms">
|
|
||||||
<input type="checkbox" id="acceptPolicies" formControlName="acceptPolicies" />
|
|
||||||
<label for="acceptPolicies">
|
|
||||||
{{ "acceptPolicies" | i18n }}<br />
|
|
||||||
<a href="https://bitwarden.com/terms/" target="_blank" rel="noreferrer">{{
|
|
||||||
"termsOfService" | i18n
|
|
||||||
}}</a
|
|
||||||
>,
|
|
||||||
<a href="https://bitwarden.com/privacy/" target="_blank" rel="noreferrer">{{
|
|
||||||
"privacyPolicy" | i18n
|
|
||||||
}}</a>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="buttons">
|
|
||||||
<button type="submit" class="btn primary block" [disabled]="form.loading">
|
|
||||||
<b [hidden]="form.loading">{{ "submit" | i18n }}</b>
|
|
||||||
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" routerLink="/login" class="btn block">{{ "cancel" | i18n }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
|
|
||||||
import { UntypedFormBuilder } from "@angular/forms";
|
|
||||||
import { Router } from "@angular/router";
|
|
||||||
|
|
||||||
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/auth/components/register.component";
|
|
||||||
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
|
|
||||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|
||||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
import { DialogService, ToastService } from "@bitwarden/components";
|
|
||||||
import { KeyService } from "@bitwarden/key-management";
|
|
||||||
|
|
||||||
const BroadcasterSubscriptionId = "RegisterComponent";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-register",
|
|
||||||
templateUrl: "register.component.html",
|
|
||||||
})
|
|
||||||
export class RegisterComponent extends BaseRegisterComponent implements OnInit, OnDestroy {
|
|
||||||
constructor(
|
|
||||||
formValidationErrorService: FormValidationErrorsService,
|
|
||||||
formBuilder: UntypedFormBuilder,
|
|
||||||
loginStrategyService: LoginStrategyServiceAbstraction,
|
|
||||||
router: Router,
|
|
||||||
i18nService: I18nService,
|
|
||||||
keyService: KeyService,
|
|
||||||
apiService: ApiService,
|
|
||||||
platformUtilsService: PlatformUtilsService,
|
|
||||||
environmentService: EnvironmentService,
|
|
||||||
private broadcasterService: BroadcasterService,
|
|
||||||
private ngZone: NgZone,
|
|
||||||
logService: LogService,
|
|
||||||
auditService: AuditService,
|
|
||||||
dialogService: DialogService,
|
|
||||||
toastService: ToastService,
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
formValidationErrorService,
|
|
||||||
formBuilder,
|
|
||||||
loginStrategyService,
|
|
||||||
router,
|
|
||||||
i18nService,
|
|
||||||
keyService,
|
|
||||||
apiService,
|
|
||||||
platformUtilsService,
|
|
||||||
environmentService,
|
|
||||||
logService,
|
|
||||||
auditService,
|
|
||||||
dialogService,
|
|
||||||
toastService,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async ngOnInit() {
|
|
||||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => {
|
|
||||||
this.ngZone.run(() => {
|
|
||||||
switch (message.command) {
|
|
||||||
case "windowHidden":
|
|
||||||
this.onWindowHidden();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
super.ngOnInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
onWindowHidden() {
|
|
||||||
this.showPassword = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,342 +0,0 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
|
||||||
import { AbstractControl, UntypedFormBuilder, ValidatorFn, Validators } from "@angular/forms";
|
|
||||||
import { Router } from "@angular/router";
|
|
||||||
|
|
||||||
import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "@bitwarden/auth/common";
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|
||||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
|
||||||
import { RegisterResponse } from "@bitwarden/common/auth/models/response/register.response";
|
|
||||||
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
|
|
||||||
import { ReferenceEventRequest } from "@bitwarden/common/models/request/reference-event.request";
|
|
||||||
import { RegisterRequest } from "@bitwarden/common/models/request/register.request";
|
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|
||||||
import { DialogService, ToastService } from "@bitwarden/components";
|
|
||||||
import { DEFAULT_KDF_CONFIG, KeyService } from "@bitwarden/key-management";
|
|
||||||
|
|
||||||
import {
|
|
||||||
AllValidationErrors,
|
|
||||||
FormValidationErrorsService,
|
|
||||||
} from "../../platform/abstractions/form-validation-errors.service";
|
|
||||||
import { PasswordColorText } from "../../tools/password-strength/password-strength.component";
|
|
||||||
import { InputsFieldMatch } from "../validators/inputs-field-match.validator";
|
|
||||||
|
|
||||||
import { CaptchaProtectedComponent } from "./captcha-protected.component";
|
|
||||||
|
|
||||||
@Directive()
|
|
||||||
export class RegisterComponent extends CaptchaProtectedComponent implements OnInit {
|
|
||||||
@Input() isInTrialFlow = false;
|
|
||||||
@Output() createdAccount = new EventEmitter<string>();
|
|
||||||
|
|
||||||
showPassword = false;
|
|
||||||
formPromise: Promise<RegisterResponse>;
|
|
||||||
referenceData: ReferenceEventRequest;
|
|
||||||
showTerms = true;
|
|
||||||
showErrorSummary = false;
|
|
||||||
passwordStrengthResult: any;
|
|
||||||
characterMinimumMessage: string;
|
|
||||||
minimumLength = Utils.minimumPasswordLength;
|
|
||||||
color: string;
|
|
||||||
text: string;
|
|
||||||
|
|
||||||
formGroup = this.formBuilder.group(
|
|
||||||
{
|
|
||||||
email: ["", [Validators.required, Validators.email]],
|
|
||||||
name: [""],
|
|
||||||
masterPassword: ["", [Validators.required, Validators.minLength(this.minimumLength)]],
|
|
||||||
confirmMasterPassword: ["", [Validators.required, Validators.minLength(this.minimumLength)]],
|
|
||||||
hint: [
|
|
||||||
null,
|
|
||||||
[
|
|
||||||
InputsFieldMatch.validateInputsDoesntMatch(
|
|
||||||
"masterPassword",
|
|
||||||
this.i18nService.t("hintEqualsPassword"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
checkForBreaches: [true],
|
|
||||||
acceptPolicies: [false, [this.acceptPoliciesValidation()]],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: InputsFieldMatch.validateFormInputsMatch(
|
|
||||||
"masterPassword",
|
|
||||||
"confirmMasterPassword",
|
|
||||||
this.i18nService.t("masterPassDoesntMatch"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
protected successRoute = "login";
|
|
||||||
|
|
||||||
protected accountCreated = false;
|
|
||||||
|
|
||||||
protected captchaBypassToken: string = null;
|
|
||||||
|
|
||||||
// allows for extending classes to modify the register request before sending
|
|
||||||
// currently used by web to add organization invitation details
|
|
||||||
protected modifyRegisterRequest: (request: RegisterRequest) => Promise<void>;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected formValidationErrorService: FormValidationErrorsService,
|
|
||||||
protected formBuilder: UntypedFormBuilder,
|
|
||||||
protected loginStrategyService: LoginStrategyServiceAbstraction,
|
|
||||||
protected router: Router,
|
|
||||||
i18nService: I18nService,
|
|
||||||
protected keyService: KeyService,
|
|
||||||
protected apiService: ApiService,
|
|
||||||
platformUtilsService: PlatformUtilsService,
|
|
||||||
environmentService: EnvironmentService,
|
|
||||||
protected logService: LogService,
|
|
||||||
protected auditService: AuditService,
|
|
||||||
protected dialogService: DialogService,
|
|
||||||
protected toastService: ToastService,
|
|
||||||
) {
|
|
||||||
super(environmentService, i18nService, platformUtilsService, toastService);
|
|
||||||
this.showTerms = !platformUtilsService.isSelfHost();
|
|
||||||
this.characterMinimumMessage = this.i18nService.t("characterMinimum", this.minimumLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
async ngOnInit() {
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.setupCaptcha();
|
|
||||||
}
|
|
||||||
|
|
||||||
async submit(showToast = true) {
|
|
||||||
let email = this.formGroup.value.email;
|
|
||||||
email = email.trim().toLowerCase();
|
|
||||||
let name = this.formGroup.value.name;
|
|
||||||
name = name === "" ? null : name; // Why do we do this?
|
|
||||||
const masterPassword = this.formGroup.value.masterPassword;
|
|
||||||
try {
|
|
||||||
if (!this.accountCreated) {
|
|
||||||
const registerResponse = await this.registerAccount(
|
|
||||||
await this.buildRegisterRequest(email, masterPassword, name),
|
|
||||||
showToast,
|
|
||||||
);
|
|
||||||
if (!registerResponse.successful) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.captchaBypassToken = registerResponse.captchaBypassToken;
|
|
||||||
this.accountCreated = true;
|
|
||||||
}
|
|
||||||
if (this.isInTrialFlow) {
|
|
||||||
if (!this.accountCreated) {
|
|
||||||
this.toastService.showToast({
|
|
||||||
variant: "success",
|
|
||||||
title: null,
|
|
||||||
message: this.i18nService.t("trialAccountCreated"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const loginResponse = await this.logIn(email, masterPassword, this.captchaBypassToken);
|
|
||||||
if (loginResponse.captchaRequired) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.createdAccount.emit(this.formGroup.value.email);
|
|
||||||
} else {
|
|
||||||
this.toastService.showToast({
|
|
||||||
variant: "success",
|
|
||||||
title: null,
|
|
||||||
message: this.i18nService.t("newAccountCreated"),
|
|
||||||
});
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.router.navigate([this.successRoute], { queryParams: { email: email } });
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.logService.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
togglePassword() {
|
|
||||||
this.showPassword = !this.showPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
getStrengthResult(result: any) {
|
|
||||||
this.passwordStrengthResult = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPasswordScoreText(event: PasswordColorText) {
|
|
||||||
this.color = event.color;
|
|
||||||
this.text = event.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getErrorToastMessage() {
|
|
||||||
const error: AllValidationErrors = this.formValidationErrorService
|
|
||||||
.getFormValidationErrors(this.formGroup.controls)
|
|
||||||
.shift();
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
switch (error.errorName) {
|
|
||||||
case "email":
|
|
||||||
return this.i18nService.t("invalidEmail");
|
|
||||||
case "inputsDoesntMatchError":
|
|
||||||
return this.i18nService.t("masterPassDoesntMatch");
|
|
||||||
case "inputsMatchError":
|
|
||||||
return this.i18nService.t("hintEqualsPassword");
|
|
||||||
case "minlength":
|
|
||||||
return this.i18nService.t("masterPasswordMinlength", Utils.minimumPasswordLength);
|
|
||||||
default:
|
|
||||||
return this.i18nService.t(this.errorTag(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
private errorTag(error: AllValidationErrors): string {
|
|
||||||
const name = error.errorName.charAt(0).toUpperCase() + error.errorName.slice(1);
|
|
||||||
return `${error.controlName}${name}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
//validation would be ignored on selfhosted
|
|
||||||
private acceptPoliciesValidation(): ValidatorFn {
|
|
||||||
return (control: AbstractControl) => {
|
|
||||||
const ctrlValue = control.value;
|
|
||||||
|
|
||||||
return !ctrlValue && this.showTerms ? { required: true } : null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async validateRegistration(showToast: boolean): Promise<{ isValid: boolean }> {
|
|
||||||
this.formGroup.markAllAsTouched();
|
|
||||||
this.showErrorSummary = true;
|
|
||||||
|
|
||||||
if (this.formGroup.get("acceptPolicies").hasError("required")) {
|
|
||||||
this.toastService.showToast({
|
|
||||||
variant: "error",
|
|
||||||
title: this.i18nService.t("errorOccurred"),
|
|
||||||
message: this.i18nService.t("acceptPoliciesRequired"),
|
|
||||||
});
|
|
||||||
return { isValid: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
//web
|
|
||||||
if (this.formGroup.invalid && !showToast) {
|
|
||||||
return { isValid: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
//desktop, browser
|
|
||||||
if (this.formGroup.invalid && showToast) {
|
|
||||||
const errorText = this.getErrorToastMessage();
|
|
||||||
this.toastService.showToast({
|
|
||||||
variant: "error",
|
|
||||||
title: this.i18nService.t("errorOccurred"),
|
|
||||||
message: errorText,
|
|
||||||
});
|
|
||||||
return { isValid: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
const passwordWeak =
|
|
||||||
this.passwordStrengthResult != null && this.passwordStrengthResult.score < 3;
|
|
||||||
const passwordLeak =
|
|
||||||
this.formGroup.controls.checkForBreaches.value &&
|
|
||||||
(await this.auditService.passwordLeaked(this.formGroup.controls.masterPassword.value)) > 0;
|
|
||||||
|
|
||||||
if (passwordWeak && passwordLeak) {
|
|
||||||
const result = await this.dialogService.openSimpleDialog({
|
|
||||||
title: { key: "weakAndExposedMasterPassword" },
|
|
||||||
content: { key: "weakAndBreachedMasterPasswordDesc" },
|
|
||||||
type: "warning",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
return { isValid: false };
|
|
||||||
}
|
|
||||||
} else if (passwordWeak) {
|
|
||||||
const result = await this.dialogService.openSimpleDialog({
|
|
||||||
title: { key: "weakMasterPassword" },
|
|
||||||
content: { key: "weakMasterPasswordDesc" },
|
|
||||||
type: "warning",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
return { isValid: false };
|
|
||||||
}
|
|
||||||
} else if (passwordLeak) {
|
|
||||||
const result = await this.dialogService.openSimpleDialog({
|
|
||||||
title: { key: "exposedMasterPassword" },
|
|
||||||
content: { key: "exposedMasterPasswordDesc" },
|
|
||||||
type: "warning",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
return { isValid: false };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { isValid: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
private async buildRegisterRequest(
|
|
||||||
email: string,
|
|
||||||
masterPassword: string,
|
|
||||||
name: string,
|
|
||||||
): Promise<RegisterRequest> {
|
|
||||||
const hint = this.formGroup.value.hint;
|
|
||||||
const kdfConfig = DEFAULT_KDF_CONFIG;
|
|
||||||
const key = await this.keyService.makeMasterKey(masterPassword, email, kdfConfig);
|
|
||||||
const newUserKey = await this.keyService.makeUserKey(key);
|
|
||||||
const masterKeyHash = await this.keyService.hashMasterKey(masterPassword, key);
|
|
||||||
const keys = await this.keyService.makeKeyPair(newUserKey[0]);
|
|
||||||
const request = new RegisterRequest(
|
|
||||||
email,
|
|
||||||
name,
|
|
||||||
masterKeyHash,
|
|
||||||
hint,
|
|
||||||
newUserKey[1].encryptedString,
|
|
||||||
this.referenceData,
|
|
||||||
this.captchaToken,
|
|
||||||
kdfConfig.kdfType,
|
|
||||||
kdfConfig.iterations,
|
|
||||||
);
|
|
||||||
request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
|
|
||||||
if (this.modifyRegisterRequest) {
|
|
||||||
await this.modifyRegisterRequest(request);
|
|
||||||
}
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async registerAccount(
|
|
||||||
request: RegisterRequest,
|
|
||||||
showToast: boolean,
|
|
||||||
): Promise<{ successful: boolean; captchaBypassToken?: string }> {
|
|
||||||
if (!(await this.validateRegistration(showToast)).isValid) {
|
|
||||||
return { successful: false };
|
|
||||||
}
|
|
||||||
this.formPromise = this.apiService.postRegister(request);
|
|
||||||
try {
|
|
||||||
const response = await this.formPromise;
|
|
||||||
return { successful: true, captchaBypassToken: response.captchaBypassToken };
|
|
||||||
} catch (e) {
|
|
||||||
if (this.handleCaptchaRequired(e)) {
|
|
||||||
return { successful: false };
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async logIn(
|
|
||||||
email: string,
|
|
||||||
masterPassword: string,
|
|
||||||
captchaBypassToken: string,
|
|
||||||
): Promise<{ captchaRequired: boolean }> {
|
|
||||||
const credentials = new PasswordLoginCredentials(
|
|
||||||
email,
|
|
||||||
masterPassword,
|
|
||||||
captchaBypassToken,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
const loginResponse = await this.loginStrategyService.logIn(credentials);
|
|
||||||
if (this.handleCaptchaRequired(loginResponse)) {
|
|
||||||
return { captchaRequired: true };
|
|
||||||
}
|
|
||||||
return { captchaRequired: false };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user