From 1685f67e9009a8a679f9e9a24dfa28d02e8c2d83 Mon Sep 17 00:00:00 2001 From: Alec Rippberger <127791530+alec-livefront@users.noreply.github.com> Date: Tue, 11 Feb 2025 10:05:21 -0600 Subject: [PATCH] refactor: [PM-17530] remove obsolete registration component Remove outdated registration components and associated routes to cleanup the codebase and eliminate legacy functionality. --- .../src/auth/popup/register.component.html | 147 -------- .../src/auth/popup/register.component.ts | 58 --- apps/browser/src/popup/app-routing.module.ts | 7 - apps/browser/src/popup/app.module.ts | 2 - apps/desktop/src/app/app-routing.module.ts | 2 - apps/desktop/src/app/app.module.ts | 2 - apps/desktop/src/auth/register.component.html | 150 -------- apps/desktop/src/auth/register.component.ts | 83 ----- .../src/auth/components/register.component.ts | 342 ------------------ 9 files changed, 793 deletions(-) delete mode 100644 apps/browser/src/auth/popup/register.component.html delete mode 100644 apps/browser/src/auth/popup/register.component.ts delete mode 100644 apps/desktop/src/auth/register.component.html delete mode 100644 apps/desktop/src/auth/register.component.ts delete mode 100644 libs/angular/src/auth/components/register.component.ts diff --git a/apps/browser/src/auth/popup/register.component.html b/apps/browser/src/auth/popup/register.component.html deleted file mode 100644 index e2f4f2e7d12..00000000000 --- a/apps/browser/src/auth/popup/register.component.html +++ /dev/null @@ -1,147 +0,0 @@ -
-
-
- -
-

- {{ "createAccount" | i18n }} -

-
- -
-
-
-
-
-
- - -
-
-
-
- - -
-
- -
-
- - -
-
- -
-
-
-
-
- - -
-
- -
-
-
- - -
-
- -
-
- - -
-
-
-
- -
-
-
-
- - -
-
-
-
-
diff --git a/apps/browser/src/auth/popup/register.component.ts b/apps/browser/src/auth/popup/register.component.ts deleted file mode 100644 index 50475b2204d..00000000000 --- a/apps/browser/src/auth/popup/register.component.ts +++ /dev/null @@ -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, - ); - } -} diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 70a78ce548f..d55a64a64eb 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -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 { LoginComponentV1 } from "../auth/popup/login-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 { SetPasswordComponent } from "../auth/popup/set-password.component"; import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component"; @@ -267,12 +266,6 @@ const routes: Routes = [ canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, }, - { - path: "register", - component: RegisterComponent, - canActivate: [unauthGuardFn(unauthRouteOverrides)], - data: { elevation: 1 } satisfies RouteDataProperties, - }, { path: "environment", component: EnvironmentComponent, diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index 15a898aef53..3046ec7916a 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -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 { LoginComponentV1 } from "../auth/popup/login-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 { SetPasswordComponent } from "../auth/popup/set-password.component"; import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component"; @@ -103,7 +102,6 @@ import "../platform/popup/locales"; LoginViaAuthRequestComponentV1, LoginComponentV1, LoginDecryptionOptionsComponentV1, - RegisterComponent, SetPasswordComponent, SsoComponentV1, TabsV2Component, diff --git a/apps/desktop/src/app/app-routing.module.ts b/apps/desktop/src/app/app-routing.module.ts index 9007759775a..0d91d864926 100644 --- a/apps/desktop/src/app/app-routing.module.ts +++ b/apps/desktop/src/app/app-routing.module.ts @@ -56,7 +56,6 @@ import { HintComponent } from "../auth/hint.component"; import { LoginDecryptionOptionsComponentV1 } from "../auth/login/login-decryption-options/login-decryption-options-v1.component"; import { LoginComponentV1 } from "../auth/login/login-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 { SetPasswordComponent } from "../auth/set-password.component"; import { SsoComponentV1 } from "../auth/sso-v1.component"; @@ -136,7 +135,6 @@ const routes: Routes = [ }, } satisfies RouteDataProperties & AnonLayoutWrapperData, }, - { path: "register", component: RegisterComponent }, { path: "new-device-notice", component: AnonLayoutWrapperComponent, diff --git a/apps/desktop/src/app/app.module.ts b/apps/desktop/src/app/app.module.ts index c07a41d4b63..ca678621d51 100644 --- a/apps/desktop/src/app/app.module.ts +++ b/apps/desktop/src/app/app.module.ts @@ -15,7 +15,6 @@ import { DeleteAccountComponent } from "../auth/delete-account.component"; import { EnvironmentComponent } from "../auth/environment.component"; import { HintComponent } from "../auth/hint.component"; import { LoginModule } from "../auth/login/login.module"; -import { RegisterComponent } from "../auth/register.component"; import { RemovePasswordComponent } from "../auth/remove-password.component"; import { SetPasswordComponent } from "../auth/set-password.component"; import { SsoComponentV1 } from "../auth/sso-v1.component"; @@ -80,7 +79,6 @@ import { SendComponent } from "./tools/send/send.component"; NavComponent, PasswordHistoryComponent, PremiumComponent, - RegisterComponent, RemovePasswordComponent, SearchComponent, SendAddEditComponent, diff --git a/apps/desktop/src/auth/register.component.html b/apps/desktop/src/auth/register.component.html deleted file mode 100644 index 9f76b9b2a4d..00000000000 --- a/apps/desktop/src/auth/register.component.html +++ /dev/null @@ -1,150 +0,0 @@ -
-
-

{{ "createAccount" | i18n }}

-
-
-
- - -
-
-
-
- - -
-
- -
-
- - -
-
- -
-
-
-
-
- - -
-
- -
-
-
- - -
-
-
-
- - -
-
-
-
- -
- -
- - -
-
- - -
-
-
diff --git a/apps/desktop/src/auth/register.component.ts b/apps/desktop/src/auth/register.component.ts deleted file mode 100644 index ee3510b0f58..00000000000 --- a/apps/desktop/src/auth/register.component.ts +++ /dev/null @@ -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; - } -} diff --git a/libs/angular/src/auth/components/register.component.ts b/libs/angular/src/auth/components/register.component.ts deleted file mode 100644 index e4787aa8c01..00000000000 --- a/libs/angular/src/auth/components/register.component.ts +++ /dev/null @@ -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(); - - showPassword = false; - formPromise: Promise; - 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; - - 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 { - 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 }; - } -}