From bb67f560f324c93a8e22b2283feef21846671034 Mon Sep 17 00:00:00 2001 From: Alec Rippberger Date: Fri, 27 Sep 2024 12:17:32 -0500 Subject: [PATCH] Implement email population on all clients add add safeProviders. --- .../src/auth/popup/register.component.ts | 4 ++- .../src/popup/services/services.module.ts | 12 +++++-- .../src/app/services/services.module.ts | 16 +++++++-- apps/desktop/src/auth/register.component.ts | 4 ++- .../register-form/register-form.component.ts | 35 ++----------------- apps/web/src/app/core/core.module.ts | 11 +++++- .../src/auth/components/register.component.ts | 29 +++++++++++++-- 7 files changed, 68 insertions(+), 43 deletions(-) diff --git a/apps/browser/src/auth/popup/register.component.ts b/apps/browser/src/auth/popup/register.component.ts index dab1e62f85..a46e44ab7d 100644 --- a/apps/browser/src/auth/popup/register.component.ts +++ b/apps/browser/src/auth/popup/register.component.ts @@ -4,7 +4,7 @@ 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 { LoginEmailService, LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -40,6 +40,7 @@ export class RegisterComponent extends BaseRegisterComponent { auditService: AuditService, dialogService: DialogService, toastService: ToastService, + loginEmailService: LoginEmailService, ) { super( formValidationErrorService, @@ -57,6 +58,7 @@ export class RegisterComponent extends BaseRegisterComponent { auditService, dialogService, toastService, + loginEmailService, ); } } diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 47782b4581..cca5651eeb 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -17,13 +17,16 @@ import { } from "@bitwarden/angular/services/injection-tokens"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; import { AnonLayoutWrapperDataService, LoginComponentService } from "@bitwarden/auth/angular"; -import { LockService, PinServiceAbstraction } from "@bitwarden/auth/common"; +import { LockService, LoginEmailService, PinServiceAbstraction } from "@bitwarden/auth/common"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service"; +import { + AccountService, + AccountService as AccountServiceAbstraction, +} from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; @@ -586,6 +589,11 @@ const safeProviders: SafeProvider[] = [ useClass: ForegroundLockService, deps: [MessageSender, MessageListener], }), + safeProvider({ + provide: LoginEmailService, + useClass: LoginEmailService, + deps: [AccountService, AuthService, StateProvider], + }), ]; @NgModule({ diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index 2299db3fcc..7e4eb28772 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -22,14 +22,21 @@ import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services. import { LoginComponentService, SetPasswordJitService } from "@bitwarden/auth/angular"; import { InternalUserDecryptionOptionsServiceAbstraction, + LoginEmailService, PinServiceAbstraction, } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { PolicyService as PolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service"; -import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service"; +import { + AccountService, + AccountService as AccountServiceAbstraction, +} from "@bitwarden/common/auth/abstractions/account.service"; +import { + AuthService, + AuthService as AuthServiceAbstraction, +} from "@bitwarden/common/auth/abstractions/auth.service"; import { KdfConfigService, KdfConfigService as KdfConfigServiceAbstraction, @@ -310,6 +317,11 @@ const safeProviders: SafeProvider[] = [ SsoLoginServiceAbstraction, ], }), + safeProvider({ + provide: LoginEmailService, + useClass: LoginEmailService, + deps: [AccountService, AuthService, StateProvider], + }), ]; @NgModule({ diff --git a/apps/desktop/src/auth/register.component.ts b/apps/desktop/src/auth/register.component.ts index e7c2cfd32b..0484274770 100644 --- a/apps/desktop/src/auth/register.component.ts +++ b/apps/desktop/src/auth/register.component.ts @@ -4,7 +4,7 @@ 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 { LoginEmailService, 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"; @@ -42,6 +42,7 @@ export class RegisterComponent extends BaseRegisterComponent implements OnInit, auditService: AuditService, dialogService: DialogService, toastService: ToastService, + loginEmailService: LoginEmailService, ) { super( formValidationErrorService, @@ -59,6 +60,7 @@ export class RegisterComponent extends BaseRegisterComponent implements OnInit, auditService, dialogService, toastService, + loginEmailService, ); } diff --git a/apps/web/src/app/auth/register-form/register-form.component.ts b/apps/web/src/app/auth/register-form/register-form.component.ts index 3e60b5fe01..60aa03465c 100644 --- a/apps/web/src/app/auth/register-form/register-form.component.ts +++ b/apps/web/src/app/auth/register-form/register-form.component.ts @@ -1,8 +1,6 @@ import { Component, Input, OnInit, OnDestroy } from "@angular/core"; import { UntypedFormBuilder } from "@angular/forms"; import { Router } from "@angular/router"; -import { Subject } from "rxjs"; -import { takeUntil } from "rxjs/operators"; import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/auth/components/register.component"; import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; @@ -11,8 +9,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { ReferenceEventRequest } from "@bitwarden/common/models/request/reference-event.request"; import { RegisterRequest } from "@bitwarden/common/models/request/register.request"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -21,7 +17,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { StateProvider } from "@bitwarden/common/platform/state"; import { DialogService, ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; @@ -31,21 +26,8 @@ import { AcceptOrganizationInviteService } from "../organization-invite/accept-o @Component({ selector: "app-register-form", templateUrl: "./register-form.component.html", - providers: [ - { - provide: LoginEmailService, - useFactory: ( - accountService: AccountService, - authService: AuthService, - stateProvider: StateProvider, - ) => new LoginEmailService(accountService, authService, stateProvider), - deps: [AccountService, AuthService, StateProvider], - }, - ], }) export class RegisterFormComponent extends BaseRegisterComponent implements OnInit, OnDestroy { - private destroy$ = new Subject(); - @Input() queryParamEmail: string; @Input() queryParamFromOrgInvite: boolean; @Input() enforcedPolicyOptions: MasterPasswordPolicyOptions; @@ -72,7 +54,7 @@ export class RegisterFormComponent extends BaseRegisterComponent implements OnIn dialogService: DialogService, acceptOrgInviteService: AcceptOrganizationInviteService, toastService: ToastService, - private loginEmailService: LoginEmailService, + loginEmailService: LoginEmailService, ) { super( formValidationErrorService, @@ -90,6 +72,7 @@ export class RegisterFormComponent extends BaseRegisterComponent implements OnIn auditService, dialogService, toastService, + loginEmailService, ); super.modifyRegisterRequest = async (request: RegisterRequest) => { // Org invites are deep linked. Non-existent accounts are redirected to the register page. @@ -115,20 +98,6 @@ export class RegisterFormComponent extends BaseRegisterComponent implements OnIn } else { this.characterMinimumMessage = this.i18nService.t("characterMinimum", this.minimumLength); } - - /** - * If the user has a login email, set the email field to the login email. - */ - this.loginEmailService.loginEmail$.pipe(takeUntil(this.destroy$)).subscribe((email) => { - if (email) { - this.formGroup.patchValue({ email }); - } - }); - } - - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); } async submit() { diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index 1f9603c53e..4531cd4451 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -23,13 +23,17 @@ import { RegistrationFinishService as RegistrationFinishServiceAbstraction, LoginComponentService, } from "@bitwarden/auth/angular"; -import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; +import { + InternalUserDecryptionOptionsServiceAbstraction, + LoginEmailService, +} from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountApiService as AccountApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/account-api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; @@ -234,6 +238,11 @@ const safeProviders: SafeProvider[] = [ SsoLoginServiceAbstraction, ], }), + safeProvider({ + provide: LoginEmailService, + useClass: LoginEmailService, + deps: [AccountService, AuthService, StateProvider], + }), ]; @NgModule({ diff --git a/libs/angular/src/auth/components/register.component.ts b/libs/angular/src/auth/components/register.component.ts index 60adcba4d9..a11d9d887c 100644 --- a/libs/angular/src/auth/components/register.component.ts +++ b/libs/angular/src/auth/components/register.component.ts @@ -1,8 +1,13 @@ -import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core"; import { AbstractControl, UntypedFormBuilder, ValidatorFn, Validators } from "@angular/forms"; import { Router } from "@angular/router"; +import { Subject, takeUntil } from "rxjs"; -import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "@bitwarden/auth/common"; +import { + LoginEmailService, + LoginStrategyServiceAbstraction, + PasswordLoginCredentials, +} from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/auth/models/domain/kdf-config"; @@ -30,7 +35,7 @@ import { InputsFieldMatch } from "../validators/inputs-field-match.validator"; import { CaptchaProtectedComponent } from "./captcha-protected.component"; @Directive() -export class RegisterComponent extends CaptchaProtectedComponent implements OnInit { +export class RegisterComponent extends CaptchaProtectedComponent implements OnInit, OnDestroy { @Input() isInTrialFlow = false; @Output() createdAccount = new EventEmitter(); @@ -78,6 +83,9 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn protected captchaBypassToken: string = null; + protected destroy$ = new Subject(); + + // allows for extending classes to modify the register request before sending // 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; @@ -98,6 +106,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn protected auditService: AuditService, protected dialogService: DialogService, protected toastService: ToastService, + protected loginEmailService: LoginEmailService, ) { super(environmentService, i18nService, platformUtilsService, toastService); this.showTerms = !platformUtilsService.isSelfHost(); @@ -108,6 +117,20 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn // 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(); + + /** + * If the user has a login email, set the email field to the login email. + */ + this.loginEmailService.loginEmail$.pipe(takeUntil(this.destroy$)).subscribe((email) => { + if (email) { + this.formGroup.patchValue({ email }); + } + }); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); } async submit(showToast = true) {