1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-02 18:17:46 +01:00

[PM-2367] [BEEEP]: Extract password strength from password-generation-service (#5502)

* Extract passwordStrength from passwordGenerationService

Extract passwordStrength from password-generation.service.ts
Create new password-strength.service.ts
Create new password-strength.service.abstraction.ts
Register new password-strength service
Fix usages in libs

* Fix usage in web

* Fix usage in desktop

* Fix usage in CLI

* Fix usage in browser

Move password-generation-factory to tools

* Fix tests

* Change dependency in jslib-services.module
This commit is contained in:
Daniel James Smith 2023-06-13 23:22:25 +02:00 committed by GitHub
parent 22caae116c
commit 72a5ba455c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 224 additions and 111 deletions

View File

@ -5,10 +5,6 @@ import {
policyServiceFactory, policyServiceFactory,
PolicyServiceInitOptions, PolicyServiceInitOptions,
} from "../../../admin-console/background/service-factories/policy-service.factory"; } from "../../../admin-console/background/service-factories/policy-service.factory";
import {
passwordGenerationServiceFactory,
PasswordGenerationServiceInitOptions,
} from "../../../background/service-factories/password-generation-service.factory";
import { import {
apiServiceFactory, apiServiceFactory,
ApiServiceInitOptions, ApiServiceInitOptions,
@ -51,6 +47,10 @@ import {
stateServiceFactory, stateServiceFactory,
StateServiceInitOptions, StateServiceInitOptions,
} from "../../../platform/background/service-factories/state-service.factory"; } from "../../../platform/background/service-factories/state-service.factory";
import {
passwordStrengthServiceFactory,
PasswordStrengthServiceInitOptions,
} from "../../../tools/background/service_factories/password-strength-service.factory";
import { import {
keyConnectorServiceFactory, keyConnectorServiceFactory,
@ -75,7 +75,7 @@ export type AuthServiceInitOptions = AuthServiceFactoyOptions &
I18nServiceInitOptions & I18nServiceInitOptions &
EncryptServiceInitOptions & EncryptServiceInitOptions &
PolicyServiceInitOptions & PolicyServiceInitOptions &
PasswordGenerationServiceInitOptions; PasswordStrengthServiceInitOptions;
export function authServiceFactory( export function authServiceFactory(
cache: { authService?: AbstractAuthService } & CachedServices, cache: { authService?: AbstractAuthService } & CachedServices,
@ -100,7 +100,7 @@ export function authServiceFactory(
await twoFactorServiceFactory(cache, opts), await twoFactorServiceFactory(cache, opts),
await i18nServiceFactory(cache, opts), await i18nServiceFactory(cache, opts),
await encryptServiceFactory(cache, opts), await encryptServiceFactory(cache, opts),
await passwordGenerationServiceFactory(cache, opts), await passwordStrengthServiceFactory(cache, opts),
await policyServiceFactory(cache, opts) await policyServiceFactory(cache, opts)
) )
); );

View File

@ -18,7 +18,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.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"; import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors";
@ -48,7 +48,7 @@ export class LockComponent extends BaseLockComponent {
ngZone: NgZone, ngZone: NgZone,
policyApiService: PolicyApiServiceAbstraction, policyApiService: PolicyApiServiceAbstraction,
policyService: InternalPolicyService, policyService: InternalPolicyService,
passwordGenerationService: PasswordGenerationServiceAbstraction, passwordStrengthService: PasswordStrengthServiceAbstraction,
private authService: AuthService, private authService: AuthService,
dialogService: DialogServiceAbstraction dialogService: DialogServiceAbstraction
) { ) {
@ -68,7 +68,7 @@ export class LockComponent extends BaseLockComponent {
ngZone, ngZone,
policyApiService, policyApiService,
policyService, policyService,
passwordGenerationService, passwordStrengthService,
dialogService dialogService
); );
this.successRoute = "/tabs/current"; this.successRoute = "/tabs/current";

View File

@ -16,11 +16,11 @@ import {
import { totpServiceFactory } from "../../auth/background/service-factories/totp-service.factory"; import { totpServiceFactory } from "../../auth/background/service-factories/totp-service.factory";
import LockedVaultPendingNotificationsItem from "../../background/models/lockedVaultPendingNotificationsItem"; import LockedVaultPendingNotificationsItem from "../../background/models/lockedVaultPendingNotificationsItem";
import { eventCollectionServiceFactory } from "../../background/service-factories/event-collection-service.factory"; 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 { Account } from "../../models/account";
import { CachedServices } from "../../platform/background/service-factories/factory-options"; import { CachedServices } from "../../platform/background/service-factories/factory-options";
import { stateServiceFactory } from "../../platform/background/service-factories/state-service.factory"; import { stateServiceFactory } from "../../platform/background/service-factories/state-service.factory";
import { BrowserApi } from "../../platform/browser/browser-api"; import { BrowserApi } from "../../platform/browser/browser-api";
import { passwordGenerationServiceFactory } from "../../tools/background/service_factories/password-generation-service.factory";
import { import {
cipherServiceFactory, cipherServiceFactory,
CipherServiceInitOptions, CipherServiceInitOptions,

View File

@ -75,6 +75,10 @@ import {
UsernameGenerationService, UsernameGenerationService,
UsernameGenerationServiceAbstraction, UsernameGenerationServiceAbstraction,
} from "@bitwarden/common/tools/generator/username"; } 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 } from "@bitwarden/common/tools/send/services/send-api.service";
import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; 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"; import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction";
@ -155,6 +159,7 @@ export default class MainBackground {
vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction; vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction;
syncService: SyncServiceAbstraction; syncService: SyncServiceAbstraction;
passwordGenerationService: PasswordGenerationServiceAbstraction; passwordGenerationService: PasswordGenerationServiceAbstraction;
passwordStrengthService: PasswordStrengthServiceAbstraction;
totpService: TotpServiceAbstraction; totpService: TotpServiceAbstraction;
autofillService: AutofillServiceAbstraction; autofillService: AutofillServiceAbstraction;
containerService: ContainerService; containerService: ContainerService;
@ -360,6 +365,9 @@ export default class MainBackground {
this.collectionService, this.collectionService,
this.policyService this.policyService
); );
this.passwordStrengthService = new PasswordStrengthService();
this.passwordGenerationService = new PasswordGenerationService( this.passwordGenerationService = new PasswordGenerationService(
this.cryptoService, this.cryptoService,
this.policyService, this.policyService,
@ -391,7 +399,7 @@ export default class MainBackground {
this.twoFactorService, this.twoFactorService,
this.i18nService, this.i18nService,
this.encryptService, this.encryptService,
this.passwordGenerationService, this.passwordStrengthService,
this.policyService this.policyService
); );

View File

@ -6,12 +6,12 @@ import { authServiceFactory } from "../../auth/background/service-factories/auth
import { autofillServiceFactory } from "../../autofill/background/service_factories/autofill-service.factory"; import { autofillServiceFactory } from "../../autofill/background/service_factories/autofill-service.factory";
import { GeneratePasswordToClipboardCommand } from "../../autofill/clipboard"; import { GeneratePasswordToClipboardCommand } from "../../autofill/clipboard";
import { AutofillTabCommand } from "../../autofill/commands/autofill-tab-command"; 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 { Account } from "../../models/account";
import { stateServiceFactory } from "../../platform/background/service-factories/state-service.factory"; 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 { CachedServices } from "../background/service-factories/factory-options";
import { logServiceFactory } from "../background/service-factories/log-service.factory"; import { logServiceFactory } from "../background/service-factories/log-service.factory";
import { BrowserApi } from "../browser/browser-api"; import { BrowserApi } from "../browser/browser-api";

View File

@ -63,6 +63,7 @@ import { ContainerService } from "@bitwarden/common/platform/services/container.
import { SearchService } from "@bitwarden/common/services/search.service"; import { SearchService } from "@bitwarden/common/services/search.service";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; 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 } from "@bitwarden/common/tools/send/services/send-api.service";
import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
import { import {
@ -287,6 +288,11 @@ function getBgService<T>(service: keyof MainBackground) {
useFactory: getBgService<PlatformUtilsService>("platformUtilsService"), useFactory: getBgService<PlatformUtilsService>("platformUtilsService"),
deps: [], deps: [],
}, },
{
provide: PasswordStrengthServiceAbstraction,
useFactory: getBgService<PasswordStrengthServiceAbstraction>("passwordStrengthService"),
deps: [],
},
{ {
provide: PasswordGenerationServiceAbstraction, provide: PasswordGenerationServiceAbstraction,
useFactory: getBgService<PasswordGenerationServiceAbstraction>("passwordGenerationService"), useFactory: getBgService<PasswordGenerationServiceAbstraction>("passwordGenerationService"),

View File

@ -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<PasswordGenerationServiceAbstraction> {
return factory(
cache,
"passwordGenerationService",
opts,
async () =>
new PasswordGenerationService(
await cryptoServiceFactory(cache, opts),
await policyServiceFactory(cache, opts),
await stateServiceFactory(cache, opts)
)
);
}

View File

@ -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<PasswordStrengthServiceAbstraction> {
return factory(cache, "passwordStrengthService", opts, async () => new PasswordStrengthService());
}

View File

@ -35,6 +35,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; 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 { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { Response } from "../../models/response"; import { Response } from "../../models/response";
@ -54,6 +55,7 @@ export class LoginCommand {
protected cryptoFunctionService: CryptoFunctionService, protected cryptoFunctionService: CryptoFunctionService,
protected environmentService: EnvironmentService, protected environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationServiceAbstraction, protected passwordGenerationService: PasswordGenerationServiceAbstraction,
protected passwordStrengthService: PasswordStrengthServiceAbstraction,
protected platformUtilsService: PlatformUtilsService, protected platformUtilsService: PlatformUtilsService,
protected stateService: StateService, protected stateService: StateService,
protected cryptoService: CryptoService, protected cryptoService: CryptoService,
@ -505,7 +507,7 @@ export class LoginCommand {
} }
// Strength & Policy Validation // Strength & Policy Validation
const strengthResult = this.passwordGenerationService.passwordStrength( const strengthResult = this.passwordStrengthService.getPasswordStrength(
masterPassword, masterPassword,
this.email this.email
); );

View File

@ -45,6 +45,10 @@ import {
PasswordGenerationService, PasswordGenerationService,
PasswordGenerationServiceAbstraction, PasswordGenerationServiceAbstraction,
} from "@bitwarden/common/tools/generator/password"; } 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 { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
import { SendService } from "@bitwarden/common/tools/send/services/send.service"; import { SendService } from "@bitwarden/common/tools/send/services/send.service";
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
@ -103,6 +107,7 @@ export class Main {
vaultTimeoutSettingsService: VaultTimeoutSettingsService; vaultTimeoutSettingsService: VaultTimeoutSettingsService;
syncService: SyncService; syncService: SyncService;
passwordGenerationService: PasswordGenerationServiceAbstraction; passwordGenerationService: PasswordGenerationServiceAbstraction;
passwordStrengthService: PasswordStrengthServiceAbstraction;
totpService: TotpService; totpService: TotpService;
containerService: ContainerService; containerService: ContainerService;
auditService: AuditService; auditService: AuditService;
@ -302,6 +307,8 @@ export class Main {
this.twoFactorService = new TwoFactorService(this.i18nService, this.platformUtilsService); this.twoFactorService = new TwoFactorService(this.i18nService, this.platformUtilsService);
this.passwordStrengthService = new PasswordStrengthService();
this.passwordGenerationService = new PasswordGenerationService( this.passwordGenerationService = new PasswordGenerationService(
this.cryptoService, this.cryptoService,
this.policyService, this.policyService,
@ -322,7 +329,7 @@ export class Main {
this.twoFactorService, this.twoFactorService,
this.i18nService, this.i18nService,
this.encryptService, this.encryptService,
this.passwordGenerationService, this.passwordStrengthService,
this.policyService this.policyService
); );

View File

@ -145,6 +145,7 @@ export class Program {
this.main.cryptoFunctionService, this.main.cryptoFunctionService,
this.main.environmentService, this.main.environmentService,
this.main.passwordGenerationService, this.main.passwordGenerationService,
this.main.passwordStrengthService,
this.main.platformUtilsService, this.main.platformUtilsService,
this.main.stateService, this.main.stateService,
this.main.cryptoService, this.main.cryptoService,

View File

@ -18,7 +18,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.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 { ElectronStateService } from "../platform/services/electron-state.service.abstraction";
import { BiometricStorageAction, BiometricMessage } from "../types/biometric-message"; import { BiometricStorageAction, BiometricMessage } from "../types/biometric-message";
@ -49,7 +49,7 @@ export class LockComponent extends BaseLockComponent {
ngZone: NgZone, ngZone: NgZone,
policyApiService: PolicyApiServiceAbstraction, policyApiService: PolicyApiServiceAbstraction,
policyService: InternalPolicyService, policyService: InternalPolicyService,
passwordGenerationService: PasswordGenerationServiceAbstraction, passwordStrengthService: PasswordStrengthServiceAbstraction,
logService: LogService, logService: LogService,
keyConnectorService: KeyConnectorService, keyConnectorService: KeyConnectorService,
dialogService: DialogServiceAbstraction dialogService: DialogServiceAbstraction
@ -70,7 +70,7 @@ export class LockComponent extends BaseLockComponent {
ngZone, ngZone,
policyApiService, policyApiService,
policyService, policyService,
passwordGenerationService, passwordStrengthService,
dialogService dialogService
); );
} }

View File

@ -4,7 +4,7 @@ import { ActivatedRoute } from "@angular/router";
import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ModalService } from "@bitwarden/angular/services/modal.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
@ -23,7 +23,7 @@ export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportCompone
constructor( constructor(
cipherService: CipherService, cipherService: CipherService,
passwordGenerationService: PasswordGenerationServiceAbstraction, passwordStrengthService: PasswordStrengthServiceAbstraction,
modalService: ModalService, modalService: ModalService,
messagingService: MessagingService, messagingService: MessagingService,
private route: ActivatedRoute, private route: ActivatedRoute,
@ -32,7 +32,7 @@ export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportCompone
) { ) {
super( super(
cipherService, cipherService,
passwordGenerationService, passwordStrengthService,
modalService, modalService,
messagingService, messagingService,
passwordRepromptService passwordRepromptService

View File

@ -16,7 +16,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.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"; import { RouterService } from "../core";
@ -42,7 +42,7 @@ export class LockComponent extends BaseLockComponent {
ngZone: NgZone, ngZone: NgZone,
policyApiService: PolicyApiServiceAbstraction, policyApiService: PolicyApiServiceAbstraction,
policyService: InternalPolicyService, policyService: InternalPolicyService,
passwordGenerationService: PasswordGenerationServiceAbstraction, passwordStrengthService: PasswordStrengthServiceAbstraction,
dialogService: DialogServiceAbstraction dialogService: DialogServiceAbstraction
) { ) {
super( super(
@ -61,7 +61,7 @@ export class LockComponent extends BaseLockComponent {
ngZone, ngZone,
policyApiService, policyApiService,
policyService, policyService,
passwordGenerationService, passwordStrengthService,
dialogService dialogService
); );
} }

View File

@ -24,6 +24,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
import { flagEnabled } from "../../../utils/flags"; import { flagEnabled } from "../../../utils/flags";
import { RouterService, StateService } from "../../core"; import { RouterService, StateService } from "../../core";
@ -50,6 +51,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
environmentService: EnvironmentService, environmentService: EnvironmentService,
passwordGenerationService: PasswordGenerationServiceAbstraction, passwordGenerationService: PasswordGenerationServiceAbstraction,
private passwordStrengthService: PasswordStrengthServiceAbstraction,
cryptoFunctionService: CryptoFunctionService, cryptoFunctionService: CryptoFunctionService,
private policyApiService: PolicyApiServiceAbstraction, private policyApiService: PolicyApiServiceAbstraction,
private policyService: InternalPolicyService, private policyService: InternalPolicyService,
@ -153,7 +155,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest
// Check master password against policy // Check master password against policy
if (this.enforcedPasswordPolicyOptions != null) { if (this.enforcedPasswordPolicyOptions != null) {
const strengthResult = this.passwordGenerationService.passwordStrength( const strengthResult = this.passwordStrengthService.getPasswordStrength(
masterPassword, masterPassword,
this.formGroup.value.email this.formGroup.value.email
); );

View File

@ -2,7 +2,7 @@ import { Component, OnInit } from "@angular/core";
import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ModalService } from "@bitwarden/angular/services/modal.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
@ -22,7 +22,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen
constructor( constructor(
protected cipherService: CipherService, protected cipherService: CipherService,
protected passwordGenerationService: PasswordGenerationServiceAbstraction, protected passwordStrengthService: PasswordStrengthServiceAbstraction,
modalService: ModalService, modalService: ModalService,
messagingService: MessagingService, messagingService: MessagingService,
passwordRepromptService: PasswordRepromptService passwordRepromptService: PasswordRepromptService
@ -77,7 +77,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen
.filter((i) => i.length >= 3); .filter((i) => i.length >= 3);
} }
} }
const result = this.passwordGenerationService.passwordStrength( const result = this.passwordStrengthService.getPasswordStrength(
c.login.password, c.login.password,
null, null,
userInput.length > 0 ? userInput : null userInput.length > 0 ? userInput : null

View File

@ -24,7 +24,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; 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"; import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog";
@ -69,7 +69,7 @@ export class LockComponent implements OnInit, OnDestroy {
protected ngZone: NgZone, protected ngZone: NgZone,
protected policyApiService: PolicyApiServiceAbstraction, protected policyApiService: PolicyApiServiceAbstraction,
protected policyService: InternalPolicyService, protected policyService: InternalPolicyService,
protected passwordGenerationService: PasswordGenerationServiceAbstraction, protected passwordStrengthService: PasswordStrengthServiceAbstraction,
protected dialogService: DialogServiceAbstraction protected dialogService: DialogServiceAbstraction
) {} ) {}
@ -333,7 +333,7 @@ export class LockComponent implements OnInit, OnDestroy {
return false; return false;
} }
const passwordStrength = this.passwordGenerationService.passwordStrength( const passwordStrength = this.passwordStrengthService.getPasswordStrength(
this.masterPassword, this.masterPassword,
this.email this.email
)?.score; )?.score;

View File

@ -118,6 +118,10 @@ import {
UsernameGenerationService, UsernameGenerationService,
UsernameGenerationServiceAbstraction, UsernameGenerationServiceAbstraction,
} from "@bitwarden/common/tools/generator/username"; } 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 } from "@bitwarden/common/tools/send/services/send-api.service";
import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/tools/send/services/send.service"; import { SendService } from "@bitwarden/common/tools/send/services/send.service";
@ -239,7 +243,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
TwoFactorServiceAbstraction, TwoFactorServiceAbstraction,
I18nServiceAbstraction, I18nServiceAbstraction,
EncryptService, EncryptService,
PasswordGenerationServiceAbstraction, PasswordStrengthServiceAbstraction,
PolicyServiceAbstraction, PolicyServiceAbstraction,
], ],
}, },
@ -359,6 +363,11 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
DevicesApiServiceAbstraction, DevicesApiServiceAbstraction,
], ],
}, },
{
provide: PasswordStrengthServiceAbstraction,
useClass: PasswordStrengthService,
deps: [],
},
{ {
provide: PasswordGenerationServiceAbstraction, provide: PasswordGenerationServiceAbstraction,
useClass: PasswordGenerationService, useClass: PasswordGenerationService,

View File

@ -1,7 +1,7 @@
import { Component, EventEmitter, Input, OnChanges, Output } from "@angular/core"; import { Component, EventEmitter, Input, OnChanges, Output } from "@angular/core";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; 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 { export interface PasswordColorText {
color: string; color: string;
@ -59,7 +59,7 @@ export class PasswordStrengthComponent implements OnChanges {
constructor( constructor(
private i18nService: I18nService, private i18nService: I18nService,
private passwordGenerationService: PasswordGenerationServiceAbstraction private passwordStrengthService: PasswordStrengthServiceAbstraction
) {} ) {}
ngOnChanges(): void { ngOnChanges(): void {
@ -96,7 +96,7 @@ export class PasswordStrengthComponent implements OnChanges {
clearTimeout(this.masterPasswordStrengthTimeout); clearTimeout(this.masterPasswordStrengthTimeout);
} }
const strengthResult = this.passwordGenerationService.passwordStrength( const strengthResult = this.passwordStrengthService.getPasswordStrength(
masterPassword, masterPassword,
this.email, this.email,
this.name?.trim().toLowerCase().split(" ") this.name?.trim().toLowerCase().split(" ")

View File

@ -11,7 +11,10 @@ import { StateService } from "../../platform/abstractions/state.service";
import { Utils } from "../../platform/misc/utils"; import { Utils } from "../../platform/misc/utils";
import { Account, AccountProfile, AccountTokens } from "../../platform/models/domain/account"; import { Account, AccountProfile, AccountTokens } from "../../platform/models/domain/account";
import { EncString } from "../../platform/models/domain/enc-string"; 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 { AuthService } from "../abstractions/auth.service";
import { TokenService } from "../abstractions/token.service"; import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service"; import { TwoFactorService } from "../abstractions/two-factor.service";
@ -85,7 +88,7 @@ describe("LogInStrategy", () => {
let twoFactorService: MockProxy<TwoFactorService>; let twoFactorService: MockProxy<TwoFactorService>;
let authService: MockProxy<AuthService>; let authService: MockProxy<AuthService>;
let policyService: MockProxy<PolicyService>; let policyService: MockProxy<PolicyService>;
let passwordGenerationService: MockProxy<PasswordGenerationService>; let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
let passwordLogInStrategy: PasswordLogInStrategy; let passwordLogInStrategy: PasswordLogInStrategy;
let credentials: PasswordLogInCredentials; let credentials: PasswordLogInCredentials;
@ -102,7 +105,7 @@ describe("LogInStrategy", () => {
twoFactorService = mock<TwoFactorService>(); twoFactorService = mock<TwoFactorService>();
authService = mock<AuthService>(); authService = mock<AuthService>();
policyService = mock<PolicyService>(); policyService = mock<PolicyService>();
passwordGenerationService = mock<PasswordGenerationService>(); passwordStrengthService = mock<PasswordStrengthService>();
appIdService.getAppId.mockResolvedValue(deviceId); appIdService.getAppId.mockResolvedValue(deviceId);
tokenService.decodeToken.calledWith(accessToken).mockResolvedValue(decodedToken); tokenService.decodeToken.calledWith(accessToken).mockResolvedValue(decodedToken);
@ -118,7 +121,7 @@ describe("LogInStrategy", () => {
logService, logService,
stateService, stateService,
twoFactorService, twoFactorService,
passwordGenerationService, passwordStrengthService,
policyService, policyService,
authService authService
); );

View File

@ -11,7 +11,10 @@ import { PlatformUtilsService } from "../../platform/abstractions/platform-utils
import { StateService } from "../../platform/abstractions/state.service"; import { StateService } from "../../platform/abstractions/state.service";
import { Utils } from "../../platform/misc/utils"; import { Utils } from "../../platform/misc/utils";
import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; 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 { AuthService } from "../abstractions/auth.service";
import { TokenService } from "../abstractions/token.service"; import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service"; import { TwoFactorService } from "../abstractions/two-factor.service";
@ -51,7 +54,7 @@ describe("PasswordLogInStrategy", () => {
let twoFactorService: MockProxy<TwoFactorService>; let twoFactorService: MockProxy<TwoFactorService>;
let authService: MockProxy<AuthService>; let authService: MockProxy<AuthService>;
let policyService: MockProxy<PolicyService>; let policyService: MockProxy<PolicyService>;
let passwordGenerationService: MockProxy<PasswordGenerationService>; let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
let passwordLogInStrategy: PasswordLogInStrategy; let passwordLogInStrategy: PasswordLogInStrategy;
let credentials: PasswordLogInCredentials; let credentials: PasswordLogInCredentials;
@ -68,7 +71,7 @@ describe("PasswordLogInStrategy", () => {
twoFactorService = mock<TwoFactorService>(); twoFactorService = mock<TwoFactorService>();
authService = mock<AuthService>(); authService = mock<AuthService>();
policyService = mock<PolicyService>(); policyService = mock<PolicyService>();
passwordGenerationService = mock<PasswordGenerationService>(); passwordStrengthService = mock<PasswordStrengthService>();
appIdService.getAppId.mockResolvedValue(deviceId); appIdService.getAppId.mockResolvedValue(deviceId);
tokenService.decodeToken.mockResolvedValue({}); tokenService.decodeToken.mockResolvedValue({});
@ -94,7 +97,7 @@ describe("PasswordLogInStrategy", () => {
logService, logService,
stateService, stateService,
twoFactorService, twoFactorService,
passwordGenerationService, passwordStrengthService,
policyService, policyService,
authService authService
); );
@ -141,7 +144,7 @@ describe("PasswordLogInStrategy", () => {
}); });
it("does not force the user to update their master password when it meets requirements", async () => { 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); policyService.evaluateMasterPassword.mockReturnValue(true);
const result = await passwordLogInStrategy.logIn(credentials); 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 () => { 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); policyService.evaluateMasterPassword.mockReturnValue(false);
const result = await passwordLogInStrategy.logIn(credentials); 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 () => { 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); policyService.evaluateMasterPassword.mockReturnValue(false);
const token2FAResponse = new IdentityTwoFactorResponse({ const token2FAResponse = new IdentityTwoFactorResponse({

View File

@ -9,7 +9,7 @@ import { MessagingService } from "../../platform/abstractions/messaging.service"
import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service";
import { StateService } from "../../platform/abstractions/state.service"; import { StateService } from "../../platform/abstractions/state.service";
import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; 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 { AuthService } from "../abstractions/auth.service";
import { TokenService } from "../abstractions/token.service"; import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service"; import { TwoFactorService } from "../abstractions/two-factor.service";
@ -54,7 +54,7 @@ export class PasswordLogInStrategy extends LogInStrategy {
logService: LogService, logService: LogService,
protected stateService: StateService, protected stateService: StateService,
twoFactorService: TwoFactorService, twoFactorService: TwoFactorService,
private passwordGenerationService: PasswordGenerationServiceAbstraction, private passwordStrengthService: PasswordStrengthServiceAbstraction,
private policyService: PolicyService, private policyService: PolicyService,
private authService: AuthService private authService: AuthService
) { ) {
@ -158,7 +158,7 @@ export class PasswordLogInStrategy extends LogInStrategy {
{ masterPassword, email }: PasswordLogInCredentials, { masterPassword, email }: PasswordLogInCredentials,
options: MasterPasswordPolicyOptions options: MasterPasswordPolicyOptions
): boolean { ): boolean {
const passwordStrength = this.passwordGenerationService.passwordStrength( const passwordStrength = this.passwordStrengthService.getPasswordStrength(
masterPassword, masterPassword,
email email
)?.score; )?.score;

View File

@ -17,7 +17,7 @@ import { PlatformUtilsService } from "../../platform/abstractions/platform-utils
import { StateService } from "../../platform/abstractions/state.service"; import { StateService } from "../../platform/abstractions/state.service";
import { Utils } from "../../platform/misc/utils"; import { Utils } from "../../platform/misc/utils";
import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; 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 { AuthService as AuthServiceAbstraction } from "../abstractions/auth.service";
import { KeyConnectorService } from "../abstractions/key-connector.service"; import { KeyConnectorService } from "../abstractions/key-connector.service";
import { TokenService } from "../abstractions/token.service"; import { TokenService } from "../abstractions/token.service";
@ -102,7 +102,7 @@ export class AuthService implements AuthServiceAbstraction {
protected twoFactorService: TwoFactorService, protected twoFactorService: TwoFactorService,
protected i18nService: I18nService, protected i18nService: I18nService,
protected encryptService: EncryptService, protected encryptService: EncryptService,
protected passwordGenerationService: PasswordGenerationServiceAbstraction, protected passwordStrengthService: PasswordStrengthServiceAbstraction,
protected policyService: PolicyService protected policyService: PolicyService
) {} ) {}
@ -133,7 +133,7 @@ export class AuthService implements AuthServiceAbstraction {
this.logService, this.logService,
this.stateService, this.stateService,
this.twoFactorService, this.twoFactorService,
this.passwordGenerationService, this.passwordStrengthService,
this.policyService, this.policyService,
this this
); );

View File

@ -1,5 +1,3 @@
import * as zxcvbn from "zxcvbn";
import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options"; import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options";
import { GeneratedPasswordHistory } from "./generated-password-history"; import { GeneratedPasswordHistory } from "./generated-password-history";
@ -17,11 +15,6 @@ export abstract class PasswordGenerationServiceAbstraction {
getHistory: () => Promise<GeneratedPasswordHistory[]>; getHistory: () => Promise<GeneratedPasswordHistory[]>;
addHistory: (password: string) => Promise<void>; addHistory: (password: string) => Promise<void>;
clear: (userId?: string) => Promise<void>; clear: (userId?: string) => Promise<void>;
passwordStrength: (
password: string,
email?: string,
userInputs?: string[]
) => zxcvbn.ZXCVBNResult;
normalizeOptions: ( normalizeOptions: (
options: PasswordGeneratorOptions, options: PasswordGeneratorOptions,
enforcedPolicyOptions: PasswordGeneratorPolicyOptions enforcedPolicyOptions: PasswordGeneratorPolicyOptions

View File

@ -1,5 +1,3 @@
import * as zxcvbn from "zxcvbn";
import { PolicyService } from "../../../admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "../../../admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "../../../admin-console/enums"; import { PolicyType } from "../../../admin-console/enums";
import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options"; 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 }); 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( normalizeOptions(
options: PasswordGeneratorOptions, options: PasswordGeneratorOptions,
enforcedPolicyOptions: PasswordGeneratorPolicyOptions enforcedPolicyOptions: PasswordGeneratorPolicyOptions
@ -476,27 +447,6 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr
this.sanitizePasswordLength(options, false); 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) { private capitalize(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1); return str.charAt(0).toUpperCase() + str.slice(1);
} }

View File

@ -0,0 +1,2 @@
export { PasswordStrengthServiceAbstraction } from "./password-strength.service.abstraction";
export { PasswordStrengthService } from "./password-strength.service";

View File

@ -0,0 +1,5 @@
import { ZXCVBNResult } from "zxcvbn";
export abstract class PasswordStrengthServiceAbstraction {
getPasswordStrength: (password: string, email?: string, userInputs?: string[]) => ZXCVBNResult;
}

View File

@ -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]/);
}
}