diff --git a/apps/browser/src/auth/background/service-factories/auth-service.factory.ts b/apps/browser/src/auth/background/service-factories/auth-service.factory.ts index eefbf8e27fb..5612cedb91c 100644 --- a/apps/browser/src/auth/background/service-factories/auth-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/auth-service.factory.ts @@ -5,10 +5,6 @@ import { policyServiceFactory, PolicyServiceInitOptions, } from "../../../admin-console/background/service-factories/policy-service.factory"; -import { - passwordGenerationServiceFactory, - PasswordGenerationServiceInitOptions, -} from "../../../background/service-factories/password-generation-service.factory"; import { apiServiceFactory, ApiServiceInitOptions, @@ -51,6 +47,10 @@ import { stateServiceFactory, StateServiceInitOptions, } from "../../../platform/background/service-factories/state-service.factory"; +import { + passwordStrengthServiceFactory, + PasswordStrengthServiceInitOptions, +} from "../../../tools/background/service_factories/password-strength-service.factory"; import { keyConnectorServiceFactory, @@ -75,7 +75,7 @@ export type AuthServiceInitOptions = AuthServiceFactoyOptions & I18nServiceInitOptions & EncryptServiceInitOptions & PolicyServiceInitOptions & - PasswordGenerationServiceInitOptions; + PasswordStrengthServiceInitOptions; export function authServiceFactory( cache: { authService?: AbstractAuthService } & CachedServices, @@ -100,7 +100,7 @@ export function authServiceFactory( await twoFactorServiceFactory(cache, opts), await i18nServiceFactory(cache, opts), await encryptServiceFactory(cache, opts), - await passwordGenerationServiceFactory(cache, opts), + await passwordStrengthServiceFactory(cache, opts), await policyServiceFactory(cache, opts) ) ); diff --git a/apps/browser/src/auth/popup/lock.component.ts b/apps/browser/src/auth/popup/lock.component.ts index d95ff79fc8f..d13609f61d4 100644 --- a/apps/browser/src/auth/popup/lock.component.ts +++ b/apps/browser/src/auth/popup/lock.component.ts @@ -18,7 +18,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors"; @@ -48,7 +48,7 @@ export class LockComponent extends BaseLockComponent { ngZone: NgZone, policyApiService: PolicyApiServiceAbstraction, policyService: InternalPolicyService, - passwordGenerationService: PasswordGenerationServiceAbstraction, + passwordStrengthService: PasswordStrengthServiceAbstraction, private authService: AuthService, dialogService: DialogServiceAbstraction ) { @@ -68,7 +68,7 @@ export class LockComponent extends BaseLockComponent { ngZone, policyApiService, policyService, - passwordGenerationService, + passwordStrengthService, dialogService ); this.successRoute = "/tabs/current"; diff --git a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts index be7dee80a07..a5cf1c70655 100644 --- a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts +++ b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts @@ -16,11 +16,11 @@ import { import { totpServiceFactory } from "../../auth/background/service-factories/totp-service.factory"; import LockedVaultPendingNotificationsItem from "../../background/models/lockedVaultPendingNotificationsItem"; import { eventCollectionServiceFactory } from "../../background/service-factories/event-collection-service.factory"; -import { passwordGenerationServiceFactory } from "../../background/service-factories/password-generation-service.factory"; import { Account } from "../../models/account"; import { CachedServices } from "../../platform/background/service-factories/factory-options"; import { stateServiceFactory } from "../../platform/background/service-factories/state-service.factory"; import { BrowserApi } from "../../platform/browser/browser-api"; +import { passwordGenerationServiceFactory } from "../../tools/background/service_factories/password-generation-service.factory"; import { cipherServiceFactory, CipherServiceInitOptions, diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 1304f82de52..4091e807f97 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -75,6 +75,10 @@ import { UsernameGenerationService, UsernameGenerationServiceAbstraction, } from "@bitwarden/common/tools/generator/username"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "@bitwarden/common/tools/password-strength"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction"; @@ -155,6 +159,7 @@ export default class MainBackground { vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction; syncService: SyncServiceAbstraction; passwordGenerationService: PasswordGenerationServiceAbstraction; + passwordStrengthService: PasswordStrengthServiceAbstraction; totpService: TotpServiceAbstraction; autofillService: AutofillServiceAbstraction; containerService: ContainerService; @@ -360,6 +365,9 @@ export default class MainBackground { this.collectionService, this.policyService ); + + this.passwordStrengthService = new PasswordStrengthService(); + this.passwordGenerationService = new PasswordGenerationService( this.cryptoService, this.policyService, @@ -391,7 +399,7 @@ export default class MainBackground { this.twoFactorService, this.i18nService, this.encryptService, - this.passwordGenerationService, + this.passwordStrengthService, this.policyService ); diff --git a/apps/browser/src/platform/listeners/on-command-listener.ts b/apps/browser/src/platform/listeners/on-command-listener.ts index 1511e937813..65af31e173c 100644 --- a/apps/browser/src/platform/listeners/on-command-listener.ts +++ b/apps/browser/src/platform/listeners/on-command-listener.ts @@ -6,12 +6,12 @@ import { authServiceFactory } from "../../auth/background/service-factories/auth import { autofillServiceFactory } from "../../autofill/background/service_factories/autofill-service.factory"; import { GeneratePasswordToClipboardCommand } from "../../autofill/clipboard"; import { AutofillTabCommand } from "../../autofill/commands/autofill-tab-command"; -import { - PasswordGenerationServiceInitOptions, - passwordGenerationServiceFactory, -} from "../../background/service-factories/password-generation-service.factory"; import { Account } from "../../models/account"; import { stateServiceFactory } from "../../platform/background/service-factories/state-service.factory"; +import { + passwordGenerationServiceFactory, + PasswordGenerationServiceInitOptions, +} from "../../tools/background/service_factories/password-generation-service.factory"; import { CachedServices } from "../background/service-factories/factory-options"; import { logServiceFactory } from "../background/service-factories/log-service.factory"; import { BrowserApi } from "../browser/browser-api"; diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 8a2a7f7a505..5a7ca533701 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -63,6 +63,7 @@ import { ContainerService } from "@bitwarden/common/platform/services/container. import { SearchService } from "@bitwarden/common/services/search.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { @@ -287,6 +288,11 @@ function getBgService(service: keyof MainBackground) { useFactory: getBgService("platformUtilsService"), deps: [], }, + { + provide: PasswordStrengthServiceAbstraction, + useFactory: getBgService("passwordStrengthService"), + deps: [], + }, { provide: PasswordGenerationServiceAbstraction, useFactory: getBgService("passwordGenerationService"), diff --git a/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts b/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts new file mode 100644 index 00000000000..b5a56dc1184 --- /dev/null +++ b/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts @@ -0,0 +1,46 @@ +import { + PasswordGenerationService, + PasswordGenerationServiceAbstraction, +} from "@bitwarden/common/tools/generator/password"; + +import { + policyServiceFactory, + PolicyServiceInitOptions, +} from "../../../admin-console/background/service-factories/policy-service.factory"; +import { + CryptoServiceInitOptions, + cryptoServiceFactory, +} from "../../../platform/background/service-factories/crypto-service.factory"; +import { + CachedServices, + factory, + FactoryOptions, +} from "../../../platform/background/service-factories/factory-options"; +import { + stateServiceFactory, + StateServiceInitOptions, +} from "../../../platform/background/service-factories/state-service.factory"; + +type PasswordGenerationServiceFactoryOptions = FactoryOptions; + +export type PasswordGenerationServiceInitOptions = PasswordGenerationServiceFactoryOptions & + CryptoServiceInitOptions & + PolicyServiceInitOptions & + StateServiceInitOptions; + +export function passwordGenerationServiceFactory( + cache: { passwordGenerationService?: PasswordGenerationServiceAbstraction } & CachedServices, + opts: PasswordGenerationServiceInitOptions +): Promise { + return factory( + cache, + "passwordGenerationService", + opts, + async () => + new PasswordGenerationService( + await cryptoServiceFactory(cache, opts), + await policyServiceFactory(cache, opts), + await stateServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts b/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts new file mode 100644 index 00000000000..3ebd4636fe3 --- /dev/null +++ b/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts @@ -0,0 +1,23 @@ +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "@bitwarden/common/tools/password-strength"; + +import { + CachedServices, + factory, + FactoryOptions, +} from "../../../platform/background/service-factories/factory-options"; + +type PasswordStrengthServiceFactoryOptions = FactoryOptions; + +export type PasswordStrengthServiceInitOptions = PasswordStrengthServiceFactoryOptions; + +export function passwordStrengthServiceFactory( + cache: { + passwordStrengthService?: PasswordStrengthServiceAbstraction; + } & CachedServices, + opts: PasswordStrengthServiceInitOptions +): Promise { + return factory(cache, "passwordStrengthService", opts, async () => new PasswordStrengthService()); +} diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index b8d8d1335fd..fe9284e2e80 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -35,6 +35,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { Response } from "../../models/response"; @@ -54,6 +55,7 @@ export class LoginCommand { protected cryptoFunctionService: CryptoFunctionService, protected environmentService: EnvironmentService, protected passwordGenerationService: PasswordGenerationServiceAbstraction, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, protected platformUtilsService: PlatformUtilsService, protected stateService: StateService, protected cryptoService: CryptoService, @@ -505,7 +507,7 @@ export class LoginCommand { } // Strength & Policy Validation - const strengthResult = this.passwordGenerationService.passwordStrength( + const strengthResult = this.passwordStrengthService.getPasswordStrength( masterPassword, this.email ); diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 956ae23b008..70b19612348 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -45,6 +45,10 @@ import { PasswordGenerationService, PasswordGenerationServiceAbstraction, } from "@bitwarden/common/tools/generator/password"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "@bitwarden/common/tools/password-strength"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; import { SendService } from "@bitwarden/common/tools/send/services/send.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -103,6 +107,7 @@ export class Main { vaultTimeoutSettingsService: VaultTimeoutSettingsService; syncService: SyncService; passwordGenerationService: PasswordGenerationServiceAbstraction; + passwordStrengthService: PasswordStrengthServiceAbstraction; totpService: TotpService; containerService: ContainerService; auditService: AuditService; @@ -302,6 +307,8 @@ export class Main { this.twoFactorService = new TwoFactorService(this.i18nService, this.platformUtilsService); + this.passwordStrengthService = new PasswordStrengthService(); + this.passwordGenerationService = new PasswordGenerationService( this.cryptoService, this.policyService, @@ -322,7 +329,7 @@ export class Main { this.twoFactorService, this.i18nService, this.encryptService, - this.passwordGenerationService, + this.passwordStrengthService, this.policyService ); diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index 122b70c7b49..700a31b3c66 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -145,6 +145,7 @@ export class Program { this.main.cryptoFunctionService, this.main.environmentService, this.main.passwordGenerationService, + this.main.passwordStrengthService, this.main.platformUtilsService, this.main.stateService, this.main.cryptoService, diff --git a/apps/desktop/src/auth/lock.component.ts b/apps/desktop/src/auth/lock.component.ts index ef8dbe967df..61f7b4bfe30 100644 --- a/apps/desktop/src/auth/lock.component.ts +++ b/apps/desktop/src/auth/lock.component.ts @@ -18,7 +18,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { ElectronStateService } from "../platform/services/electron-state.service.abstraction"; import { BiometricStorageAction, BiometricMessage } from "../types/biometric-message"; @@ -49,7 +49,7 @@ export class LockComponent extends BaseLockComponent { ngZone: NgZone, policyApiService: PolicyApiServiceAbstraction, policyService: InternalPolicyService, - passwordGenerationService: PasswordGenerationServiceAbstraction, + passwordStrengthService: PasswordStrengthServiceAbstraction, logService: LogService, keyConnectorService: KeyConnectorService, dialogService: DialogServiceAbstraction @@ -70,7 +70,7 @@ export class LockComponent extends BaseLockComponent { ngZone, policyApiService, policyService, - passwordGenerationService, + passwordStrengthService, dialogService ); } diff --git a/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts index 8f545beb38f..68619b27514 100644 --- a/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from "@angular/router"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; @@ -23,7 +23,7 @@ export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportCompone constructor( cipherService: CipherService, - passwordGenerationService: PasswordGenerationServiceAbstraction, + passwordStrengthService: PasswordStrengthServiceAbstraction, modalService: ModalService, messagingService: MessagingService, private route: ActivatedRoute, @@ -32,7 +32,7 @@ export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportCompone ) { super( cipherService, - passwordGenerationService, + passwordStrengthService, modalService, messagingService, passwordRepromptService diff --git a/apps/web/src/app/auth/lock.component.ts b/apps/web/src/app/auth/lock.component.ts index dbb6b118ca4..789ebc16955 100644 --- a/apps/web/src/app/auth/lock.component.ts +++ b/apps/web/src/app/auth/lock.component.ts @@ -16,7 +16,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { RouterService } from "../core"; @@ -42,7 +42,7 @@ export class LockComponent extends BaseLockComponent { ngZone: NgZone, policyApiService: PolicyApiServiceAbstraction, policyService: InternalPolicyService, - passwordGenerationService: PasswordGenerationServiceAbstraction, + passwordStrengthService: PasswordStrengthServiceAbstraction, dialogService: DialogServiceAbstraction ) { super( @@ -61,7 +61,7 @@ export class LockComponent extends BaseLockComponent { ngZone, policyApiService, policyService, - passwordGenerationService, + passwordStrengthService, dialogService ); } diff --git a/apps/web/src/app/auth/login/login.component.ts b/apps/web/src/app/auth/login/login.component.ts index 52ee5a89bdd..316b353c490 100644 --- a/apps/web/src/app/auth/login/login.component.ts +++ b/apps/web/src/app/auth/login/login.component.ts @@ -24,6 +24,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { flagEnabled } from "../../../utils/flags"; import { RouterService, StateService } from "../../core"; @@ -50,6 +51,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService, passwordGenerationService: PasswordGenerationServiceAbstraction, + private passwordStrengthService: PasswordStrengthServiceAbstraction, cryptoFunctionService: CryptoFunctionService, private policyApiService: PolicyApiServiceAbstraction, private policyService: InternalPolicyService, @@ -153,7 +155,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest // Check master password against policy if (this.enforcedPasswordPolicyOptions != null) { - const strengthResult = this.passwordGenerationService.passwordStrength( + const strengthResult = this.passwordStrengthService.getPasswordStrength( masterPassword, this.formGroup.value.email ); diff --git a/apps/web/src/app/reports/pages/weak-passwords-report.component.ts b/apps/web/src/app/reports/pages/weak-passwords-report.component.ts index 14d159deee3..ddea66a6a91 100644 --- a/apps/web/src/app/reports/pages/weak-passwords-report.component.ts +++ b/apps/web/src/app/reports/pages/weak-passwords-report.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from "@angular/core"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; @@ -22,7 +22,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen constructor( protected cipherService: CipherService, - protected passwordGenerationService: PasswordGenerationServiceAbstraction, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, modalService: ModalService, messagingService: MessagingService, passwordRepromptService: PasswordRepromptService @@ -77,7 +77,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen .filter((i) => i.length >= 3); } } - const result = this.passwordGenerationService.passwordStrength( + const result = this.passwordStrengthService.getPasswordStrength( c.login.password, null, userInput.length > 0 ? userInput : null diff --git a/libs/angular/src/auth/components/lock.component.ts b/libs/angular/src/auth/components/lock.component.ts index 9114539d7a8..01c083ee5a9 100644 --- a/libs/angular/src/auth/components/lock.component.ts +++ b/libs/angular/src/auth/components/lock.component.ts @@ -24,7 +24,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog"; @@ -69,7 +69,7 @@ export class LockComponent implements OnInit, OnDestroy { protected ngZone: NgZone, protected policyApiService: PolicyApiServiceAbstraction, protected policyService: InternalPolicyService, - protected passwordGenerationService: PasswordGenerationServiceAbstraction, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, protected dialogService: DialogServiceAbstraction ) {} @@ -333,7 +333,7 @@ export class LockComponent implements OnInit, OnDestroy { return false; } - const passwordStrength = this.passwordGenerationService.passwordStrength( + const passwordStrength = this.passwordStrengthService.getPasswordStrength( this.masterPassword, this.email )?.score; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 51e3cdc3fc0..bf5cb5a09a1 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -118,6 +118,10 @@ import { UsernameGenerationService, UsernameGenerationServiceAbstraction, } from "@bitwarden/common/tools/generator/username"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "@bitwarden/common/tools/password-strength"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendService } from "@bitwarden/common/tools/send/services/send.service"; @@ -239,7 +243,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction"; TwoFactorServiceAbstraction, I18nServiceAbstraction, EncryptService, - PasswordGenerationServiceAbstraction, + PasswordStrengthServiceAbstraction, PolicyServiceAbstraction, ], }, @@ -359,6 +363,11 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction"; DevicesApiServiceAbstraction, ], }, + { + provide: PasswordStrengthServiceAbstraction, + useClass: PasswordStrengthService, + deps: [], + }, { provide: PasswordGenerationServiceAbstraction, useClass: PasswordGenerationService, diff --git a/libs/angular/src/shared/components/password-strength/password-strength.component.ts b/libs/angular/src/shared/components/password-strength/password-strength.component.ts index 91167ffc5c1..75dd687efe4 100644 --- a/libs/angular/src/shared/components/password-strength/password-strength.component.ts +++ b/libs/angular/src/shared/components/password-strength/password-strength.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, OnChanges, Output } from "@angular/core"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; export interface PasswordColorText { color: string; @@ -59,7 +59,7 @@ export class PasswordStrengthComponent implements OnChanges { constructor( private i18nService: I18nService, - private passwordGenerationService: PasswordGenerationServiceAbstraction + private passwordStrengthService: PasswordStrengthServiceAbstraction ) {} ngOnChanges(): void { @@ -96,7 +96,7 @@ export class PasswordStrengthComponent implements OnChanges { clearTimeout(this.masterPasswordStrengthTimeout); } - const strengthResult = this.passwordGenerationService.passwordStrength( + const strengthResult = this.passwordStrengthService.getPasswordStrength( masterPassword, this.email, this.name?.trim().toLowerCase().split(" ") diff --git a/libs/common/src/auth/login-strategies/login.strategy.spec.ts b/libs/common/src/auth/login-strategies/login.strategy.spec.ts index 09756fbd995..ed958af6c7d 100644 --- a/libs/common/src/auth/login-strategies/login.strategy.spec.ts +++ b/libs/common/src/auth/login-strategies/login.strategy.spec.ts @@ -11,7 +11,10 @@ import { StateService } from "../../platform/abstractions/state.service"; import { Utils } from "../../platform/misc/utils"; import { Account, AccountProfile, AccountTokens } from "../../platform/models/domain/account"; import { EncString } from "../../platform/models/domain/enc-string"; -import { PasswordGenerationService } from "../../tools/generator/password"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "../../tools/password-strength"; import { AuthService } from "../abstractions/auth.service"; import { TokenService } from "../abstractions/token.service"; import { TwoFactorService } from "../abstractions/two-factor.service"; @@ -85,7 +88,7 @@ describe("LogInStrategy", () => { let twoFactorService: MockProxy; let authService: MockProxy; let policyService: MockProxy; - let passwordGenerationService: MockProxy; + let passwordStrengthService: MockProxy; let passwordLogInStrategy: PasswordLogInStrategy; let credentials: PasswordLogInCredentials; @@ -102,7 +105,7 @@ describe("LogInStrategy", () => { twoFactorService = mock(); authService = mock(); policyService = mock(); - passwordGenerationService = mock(); + passwordStrengthService = mock(); appIdService.getAppId.mockResolvedValue(deviceId); tokenService.decodeToken.calledWith(accessToken).mockResolvedValue(decodedToken); @@ -118,7 +121,7 @@ describe("LogInStrategy", () => { logService, stateService, twoFactorService, - passwordGenerationService, + passwordStrengthService, policyService, authService ); diff --git a/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts b/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts index 0c2d1e2d575..9e3ff7da686 100644 --- a/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts +++ b/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts @@ -11,7 +11,10 @@ import { PlatformUtilsService } from "../../platform/abstractions/platform-utils import { StateService } from "../../platform/abstractions/state.service"; import { Utils } from "../../platform/misc/utils"; import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { PasswordGenerationService } from "../../tools/generator/password"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "../../tools/password-strength"; import { AuthService } from "../abstractions/auth.service"; import { TokenService } from "../abstractions/token.service"; import { TwoFactorService } from "../abstractions/two-factor.service"; @@ -51,7 +54,7 @@ describe("PasswordLogInStrategy", () => { let twoFactorService: MockProxy; let authService: MockProxy; let policyService: MockProxy; - let passwordGenerationService: MockProxy; + let passwordStrengthService: MockProxy; let passwordLogInStrategy: PasswordLogInStrategy; let credentials: PasswordLogInCredentials; @@ -68,7 +71,7 @@ describe("PasswordLogInStrategy", () => { twoFactorService = mock(); authService = mock(); policyService = mock(); - passwordGenerationService = mock(); + passwordStrengthService = mock(); appIdService.getAppId.mockResolvedValue(deviceId); tokenService.decodeToken.mockResolvedValue({}); @@ -94,7 +97,7 @@ describe("PasswordLogInStrategy", () => { logService, stateService, twoFactorService, - passwordGenerationService, + passwordStrengthService, policyService, authService ); @@ -141,7 +144,7 @@ describe("PasswordLogInStrategy", () => { }); it("does not force the user to update their master password when it meets requirements", async () => { - passwordGenerationService.passwordStrength.mockReturnValue({ score: 5 } as any); + passwordStrengthService.getPasswordStrength.mockReturnValue({ score: 5 } as any); policyService.evaluateMasterPassword.mockReturnValue(true); const result = await passwordLogInStrategy.logIn(credentials); @@ -151,7 +154,7 @@ describe("PasswordLogInStrategy", () => { }); it("forces the user to update their master password on successful login when it does not meet master password policy requirements", async () => { - passwordGenerationService.passwordStrength.mockReturnValue({ score: 0 } as any); + passwordStrengthService.getPasswordStrength.mockReturnValue({ score: 0 } as any); policyService.evaluateMasterPassword.mockReturnValue(false); const result = await passwordLogInStrategy.logIn(credentials); @@ -164,7 +167,7 @@ describe("PasswordLogInStrategy", () => { }); it("forces the user to update their master password on successful 2FA login when it does not meet master password policy requirements", async () => { - passwordGenerationService.passwordStrength.mockReturnValue({ score: 0 } as any); + passwordStrengthService.getPasswordStrength.mockReturnValue({ score: 0 } as any); policyService.evaluateMasterPassword.mockReturnValue(false); const token2FAResponse = new IdentityTwoFactorResponse({ diff --git a/libs/common/src/auth/login-strategies/password-login.strategy.ts b/libs/common/src/auth/login-strategies/password-login.strategy.ts index 200656a08ff..41f7c30ec7e 100644 --- a/libs/common/src/auth/login-strategies/password-login.strategy.ts +++ b/libs/common/src/auth/login-strategies/password-login.strategy.ts @@ -9,7 +9,7 @@ import { MessagingService } from "../../platform/abstractions/messaging.service" import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; import { StateService } from "../../platform/abstractions/state.service"; import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { PasswordGenerationServiceAbstraction } from "../../tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "../../tools/password-strength"; import { AuthService } from "../abstractions/auth.service"; import { TokenService } from "../abstractions/token.service"; import { TwoFactorService } from "../abstractions/two-factor.service"; @@ -54,7 +54,7 @@ export class PasswordLogInStrategy extends LogInStrategy { logService: LogService, protected stateService: StateService, twoFactorService: TwoFactorService, - private passwordGenerationService: PasswordGenerationServiceAbstraction, + private passwordStrengthService: PasswordStrengthServiceAbstraction, private policyService: PolicyService, private authService: AuthService ) { @@ -158,7 +158,7 @@ export class PasswordLogInStrategy extends LogInStrategy { { masterPassword, email }: PasswordLogInCredentials, options: MasterPasswordPolicyOptions ): boolean { - const passwordStrength = this.passwordGenerationService.passwordStrength( + const passwordStrength = this.passwordStrengthService.getPasswordStrength( masterPassword, email )?.score; diff --git a/libs/common/src/auth/services/auth.service.ts b/libs/common/src/auth/services/auth.service.ts index 6650ce798ea..56f601da56f 100644 --- a/libs/common/src/auth/services/auth.service.ts +++ b/libs/common/src/auth/services/auth.service.ts @@ -17,7 +17,7 @@ import { PlatformUtilsService } from "../../platform/abstractions/platform-utils import { StateService } from "../../platform/abstractions/state.service"; import { Utils } from "../../platform/misc/utils"; import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { PasswordGenerationServiceAbstraction } from "../../tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "../../tools/password-strength"; import { AuthService as AuthServiceAbstraction } from "../abstractions/auth.service"; import { KeyConnectorService } from "../abstractions/key-connector.service"; import { TokenService } from "../abstractions/token.service"; @@ -102,7 +102,7 @@ export class AuthService implements AuthServiceAbstraction { protected twoFactorService: TwoFactorService, protected i18nService: I18nService, protected encryptService: EncryptService, - protected passwordGenerationService: PasswordGenerationServiceAbstraction, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, protected policyService: PolicyService ) {} @@ -133,7 +133,7 @@ export class AuthService implements AuthServiceAbstraction { this.logService, this.stateService, this.twoFactorService, - this.passwordGenerationService, + this.passwordStrengthService, this.policyService, this ); diff --git a/libs/common/src/tools/generator/password/password-generation.service.abstraction.ts b/libs/common/src/tools/generator/password/password-generation.service.abstraction.ts index 7de8c28ed72..3f2c8424ad0 100644 --- a/libs/common/src/tools/generator/password/password-generation.service.abstraction.ts +++ b/libs/common/src/tools/generator/password/password-generation.service.abstraction.ts @@ -1,5 +1,3 @@ -import * as zxcvbn from "zxcvbn"; - import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options"; import { GeneratedPasswordHistory } from "./generated-password-history"; @@ -17,11 +15,6 @@ export abstract class PasswordGenerationServiceAbstraction { getHistory: () => Promise; addHistory: (password: string) => Promise; clear: (userId?: string) => Promise; - passwordStrength: ( - password: string, - email?: string, - userInputs?: string[] - ) => zxcvbn.ZXCVBNResult; normalizeOptions: ( options: PasswordGeneratorOptions, enforcedPolicyOptions: PasswordGeneratorPolicyOptions diff --git a/libs/common/src/tools/generator/password/password-generation.service.ts b/libs/common/src/tools/generator/password/password-generation.service.ts index 8270e2d812e..079d455c46d 100644 --- a/libs/common/src/tools/generator/password/password-generation.service.ts +++ b/libs/common/src/tools/generator/password/password-generation.service.ts @@ -1,5 +1,3 @@ -import * as zxcvbn from "zxcvbn"; - import { PolicyService } from "../../../admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "../../../admin-console/enums"; import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options"; @@ -387,33 +385,6 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr await this.stateService.setDecryptedPasswordGenerationHistory(null, { userId: userId }); } - /** - * Calculates a password strength score using zxcvbn. - * @param password The password to calculate the strength of. - * @param emailInput An unparsed email address to use as user input. - * @param userInputs An array of additional user inputs to use when calculating the strength. - */ - passwordStrength( - password: string, - emailInput: string = null, - userInputs: string[] = null - ): zxcvbn.ZXCVBNResult { - if (password == null || password.length === 0) { - return null; - } - const globalUserInputs = [ - "bitwarden", - "bit", - "warden", - ...(userInputs ?? []), - ...this.emailToUserInputs(emailInput), - ]; - // Use a hash set to get rid of any duplicate user inputs - const finalUserInputs = Array.from(new Set(globalUserInputs)); - const result = zxcvbn(password, finalUserInputs); - return result; - } - normalizeOptions( options: PasswordGeneratorOptions, enforcedPolicyOptions: PasswordGeneratorPolicyOptions @@ -476,27 +447,6 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr this.sanitizePasswordLength(options, false); } - /** - * Convert an email address into a list of user inputs for zxcvbn by - * taking the local part of the email address and splitting it into words. - * @param email - * @private - */ - private emailToUserInputs(email: string): string[] { - if (email == null || email.length === 0) { - return []; - } - const atPosition = email.indexOf("@"); - if (atPosition < 0) { - return []; - } - return email - .substring(0, atPosition) - .trim() - .toLowerCase() - .split(/[^A-Za-z0-9]/); - } - private capitalize(str: string) { return str.charAt(0).toUpperCase() + str.slice(1); } diff --git a/libs/common/src/tools/password-strength/index.ts b/libs/common/src/tools/password-strength/index.ts new file mode 100644 index 00000000000..3e160fa8204 --- /dev/null +++ b/libs/common/src/tools/password-strength/index.ts @@ -0,0 +1,2 @@ +export { PasswordStrengthServiceAbstraction } from "./password-strength.service.abstraction"; +export { PasswordStrengthService } from "./password-strength.service"; diff --git a/libs/common/src/tools/password-strength/password-strength.service.abstraction.ts b/libs/common/src/tools/password-strength/password-strength.service.abstraction.ts new file mode 100644 index 00000000000..5708a4c7bd1 --- /dev/null +++ b/libs/common/src/tools/password-strength/password-strength.service.abstraction.ts @@ -0,0 +1,5 @@ +import { ZXCVBNResult } from "zxcvbn"; + +export abstract class PasswordStrengthServiceAbstraction { + getPasswordStrength: (password: string, email?: string, userInputs?: string[]) => ZXCVBNResult; +} diff --git a/libs/common/src/tools/password-strength/password-strength.service.ts b/libs/common/src/tools/password-strength/password-strength.service.ts new file mode 100644 index 00000000000..78a8f963991 --- /dev/null +++ b/libs/common/src/tools/password-strength/password-strength.service.ts @@ -0,0 +1,53 @@ +import * as zxcvbn from "zxcvbn"; + +import { PasswordStrengthServiceAbstraction } from "./password-strength.service.abstraction"; + +export class PasswordStrengthService implements PasswordStrengthServiceAbstraction { + /** + * Calculates a password strength score using zxcvbn. + * @param password The password to calculate the strength of. + * @param emailInput An unparsed email address to use as user input. + * @param userInputs An array of additional user inputs to use when calculating the strength. + */ + getPasswordStrength( + password: string, + emailInput: string = null, + userInputs: string[] = null + ): zxcvbn.ZXCVBNResult { + if (password == null || password.length === 0) { + return null; + } + const globalUserInputs = [ + "bitwarden", + "bit", + "warden", + ...(userInputs ?? []), + ...this.emailToUserInputs(emailInput), + ]; + // Use a hash set to get rid of any duplicate user inputs + const finalUserInputs = Array.from(new Set(globalUserInputs)); + const result = zxcvbn(password, finalUserInputs); + return result; + } + + /** + * Convert an email address into a list of user inputs for zxcvbn by + * taking the local part of the email address and splitting it into words. + * @param email + * @private + */ + private emailToUserInputs(email: string): string[] { + if (email == null || email.length === 0) { + return []; + } + const atPosition = email.indexOf("@"); + if (atPosition < 0) { + return []; + } + return email + .substring(0, atPosition) + .trim() + .toLowerCase() + .split(/[^A-Za-z0-9]/); + } +}