1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-27 04:03:00 +02: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,
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)
)
);

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 { 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";

View File

@ -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,

View File

@ -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
);

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 { 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";

View File

@ -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<T>(service: keyof MainBackground) {
useFactory: getBgService<PlatformUtilsService>("platformUtilsService"),
deps: [],
},
{
provide: PasswordStrengthServiceAbstraction,
useFactory: getBgService<PasswordStrengthServiceAbstraction>("passwordStrengthService"),
deps: [],
},
{
provide: PasswordGenerationServiceAbstraction,
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 { 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
);

View File

@ -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
);

View File

@ -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,

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 { 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
);
}

View File

@ -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

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 { 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
);
}

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 { 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
);

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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(" ")

View File

@ -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<TwoFactorService>;
let authService: MockProxy<AuthService>;
let policyService: MockProxy<PolicyService>;
let passwordGenerationService: MockProxy<PasswordGenerationService>;
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
let passwordLogInStrategy: PasswordLogInStrategy;
let credentials: PasswordLogInCredentials;
@ -102,7 +105,7 @@ describe("LogInStrategy", () => {
twoFactorService = mock<TwoFactorService>();
authService = mock<AuthService>();
policyService = mock<PolicyService>();
passwordGenerationService = mock<PasswordGenerationService>();
passwordStrengthService = mock<PasswordStrengthService>();
appIdService.getAppId.mockResolvedValue(deviceId);
tokenService.decodeToken.calledWith(accessToken).mockResolvedValue(decodedToken);
@ -118,7 +121,7 @@ describe("LogInStrategy", () => {
logService,
stateService,
twoFactorService,
passwordGenerationService,
passwordStrengthService,
policyService,
authService
);

View File

@ -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<TwoFactorService>;
let authService: MockProxy<AuthService>;
let policyService: MockProxy<PolicyService>;
let passwordGenerationService: MockProxy<PasswordGenerationService>;
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
let passwordLogInStrategy: PasswordLogInStrategy;
let credentials: PasswordLogInCredentials;
@ -68,7 +71,7 @@ describe("PasswordLogInStrategy", () => {
twoFactorService = mock<TwoFactorService>();
authService = mock<AuthService>();
policyService = mock<PolicyService>();
passwordGenerationService = mock<PasswordGenerationService>();
passwordStrengthService = mock<PasswordStrengthService>();
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({

View File

@ -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;

View File

@ -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
);

View File

@ -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<GeneratedPasswordHistory[]>;
addHistory: (password: string) => Promise<void>;
clear: (userId?: string) => Promise<void>;
passwordStrength: (
password: string,
email?: string,
userInputs?: string[]
) => zxcvbn.ZXCVBNResult;
normalizeOptions: (
options: PasswordGeneratorOptions,
enforcedPolicyOptions: PasswordGeneratorPolicyOptions

View File

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

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