1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-22 03:03:43 +00:00

[PM-8524] Migrate password/username generation to CipherFormGenerationService

This commit is contained in:
Shane Melton
2024-07-11 12:40:36 -07:00
parent 39ac6061ca
commit 9c1c85155b
6 changed files with 78 additions and 30 deletions

View File

@@ -0,0 +1,20 @@
/**
* Service responsible for generating random passwords and usernames.
*/
export abstract class CipherFormGenerationService {
/**
* Generates a random password. Called when the user clicks the "Generate Password" button in the UI.
*/
abstract generatePassword(): Promise<string | null>;
/**
* Generates a random username. Called when the user clicks the "Generate Username" button in the UI.
*/
abstract generateUsername(): Promise<string | null>;
/**
* Generates an initial password for a new cipher. This should not involve any user interaction as it will
* be used to pre-fill the password field in the UI for new Login ciphers.
*/
abstract generateInitialPassword(): Promise<string | null>;
}

View File

@@ -1,7 +1,9 @@
import { NgModule } from "@angular/core"; import { NgModule } from "@angular/core";
import { CipherFormGenerationService } from "./abstractions/cipher-form-generation.service";
import { CipherFormService } from "./abstractions/cipher-form.service"; import { CipherFormService } from "./abstractions/cipher-form.service";
import { CipherFormComponent } from "./components/cipher-form.component"; import { CipherFormComponent } from "./components/cipher-form.component";
import { DefaultCipherFormGenerationService } from "./services/default-cipher-form-generation.service";
import { DefaultCipherFormService } from "./services/default-cipher-form.service"; import { DefaultCipherFormService } from "./services/default-cipher-form.service";
@NgModule({ @NgModule({
@@ -11,6 +13,10 @@ import { DefaultCipherFormService } from "./services/default-cipher-form.service
provide: CipherFormService, provide: CipherFormService,
useClass: DefaultCipherFormService, useClass: DefaultCipherFormService,
}, },
{
provide: CipherFormGenerationService,
useClass: DefaultCipherFormGenerationService,
},
], ],
exports: [CipherFormComponent], exports: [CipherFormComponent],
}) })

View File

@@ -19,10 +19,10 @@ import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
import { AsyncActionsModule, ButtonModule, ToastService } from "@bitwarden/components"; import { AsyncActionsModule, ButtonModule, ToastService } from "@bitwarden/components";
import { import {
PasswordGenerationServiceAbstraction, CipherFormConfig,
UsernameGenerationServiceAbstraction, CipherFormGenerationService,
} from "@bitwarden/generator-legacy"; PasswordRepromptService,
import { CipherFormConfig, PasswordRepromptService } from "@bitwarden/vault"; } from "@bitwarden/vault";
import { PreloadedEnglishI18nModule } from "@bitwarden/web-vault/src/app/core/tests"; import { PreloadedEnglishI18nModule } from "@bitwarden/web-vault/src/app/core/tests";
import { CipherFormService } from "./abstractions/cipher-form.service"; import { CipherFormService } from "./abstractions/cipher-form.service";
@@ -132,23 +132,17 @@ export default {
}, },
}, },
{ {
provide: PasswordGenerationServiceAbstraction, provide: CipherFormGenerationService,
useValue: { useValue: {
getOptions: () => Promise.resolve([{}, {}]), generateInitialPassword: () => Promise.resolve("initial-password"),
generatePassword: () => Promise.resolve("random-password"), generatePassword: () => Promise.resolve("random-password"),
},
},
{
provide: UsernameGenerationServiceAbstraction,
useValue: {
getOptions: () => Promise.resolve({}),
generateUsername: () => Promise.resolve("random-username"), generateUsername: () => Promise.resolve("random-username"),
}, },
}, },
{ {
provide: TotpCaptureService, provide: TotpCaptureService,
useValue: { useValue: {
captureTotpFromTab: () => Promise.resolve("some-value"), captureTotpSecret: () => Promise.resolve("some-value"),
}, },
}, },
{ {

View File

@@ -19,11 +19,8 @@ import {
ToastService, ToastService,
TypographyModule, TypographyModule,
} from "@bitwarden/components"; } from "@bitwarden/components";
import {
PasswordGenerationServiceAbstraction,
UsernameGenerationServiceAbstraction,
} from "@bitwarden/generator-legacy";
import { CipherFormGenerationService } from "../../abstractions/cipher-form-generation.service";
import { TotpCaptureService } from "../../abstractions/totp-capture.service"; import { TotpCaptureService } from "../../abstractions/totp-capture.service";
import { CipherFormContainer } from "../../cipher-form-container"; import { CipherFormContainer } from "../../cipher-form-container";
@@ -88,8 +85,7 @@ export class LoginDetailsSectionComponent implements OnInit {
private cipherFormContainer: CipherFormContainer, private cipherFormContainer: CipherFormContainer,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private i18nService: I18nService, private i18nService: I18nService,
private passwordGenerationService: PasswordGenerationServiceAbstraction, private generationService: CipherFormGenerationService,
private usernameGenerationService: UsernameGenerationServiceAbstraction,
private auditService: AuditService, private auditService: AuditService,
private toastService: ToastService, private toastService: ToastService,
@Optional() private totpCaptureService?: TotpCaptureService, @Optional() private totpCaptureService?: TotpCaptureService,
@@ -145,7 +141,9 @@ export class LoginDetailsSectionComponent implements OnInit {
} }
private async initNewCipher() { private async initNewCipher() {
this.loginDetailsForm.controls.password.patchValue(await this.generateNewPassword()); this.loginDetailsForm.controls.password.patchValue(
await this.generationService.generateInitialPassword(),
);
} }
captureTotp = async () => { captureTotp = async () => {
@@ -184,8 +182,11 @@ export class LoginDetailsSectionComponent implements OnInit {
* TODO: Browser extension needs a means to cache the current form so values are not lost upon navigating to the generator. * TODO: Browser extension needs a means to cache the current form so values are not lost upon navigating to the generator.
*/ */
generatePassword = async () => { generatePassword = async () => {
const newPassword = await this.generateNewPassword(); const newPassword = await this.generationService.generatePassword();
if (newPassword) {
this.loginDetailsForm.controls.password.patchValue(newPassword); this.loginDetailsForm.controls.password.patchValue(newPassword);
}
}; };
/** /**
@@ -193,9 +194,10 @@ export class LoginDetailsSectionComponent implements OnInit {
* TODO: Browser extension needs a means to cache the current form so values are not lost upon navigating to the generator. * TODO: Browser extension needs a means to cache the current form so values are not lost upon navigating to the generator.
*/ */
generateUsername = async () => { generateUsername = async () => {
const options = await this.usernameGenerationService.getOptions(); const newUsername = await this.generationService.generateUsername();
const newUsername = await this.usernameGenerationService.generateUsername(options); if (newUsername) {
this.loginDetailsForm.controls.username.patchValue(newUsername); this.loginDetailsForm.controls.username.patchValue(newUsername);
}
}; };
/** /**
@@ -224,9 +226,4 @@ export class LoginDetailsSectionComponent implements OnInit {
}); });
} }
}; };
private async generateNewPassword() {
const [options] = await this.passwordGenerationService.getOptions();
return await this.passwordGenerationService.generatePassword(options);
}
} }

View File

@@ -6,4 +6,5 @@ export {
OptionalInitialValues, OptionalInitialValues,
} from "./abstractions/cipher-form-config.service"; } from "./abstractions/cipher-form-config.service";
export { TotpCaptureService } from "./abstractions/totp-capture.service"; export { TotpCaptureService } from "./abstractions/totp-capture.service";
export { CipherFormGenerationService } from "./abstractions/cipher-form-generation.service";
export { DefaultCipherFormConfigService } from "./services/default-cipher-form-config.service"; export { DefaultCipherFormConfigService } from "./services/default-cipher-form-config.service";

View File

@@ -0,0 +1,30 @@
import { Injectable } from "@angular/core";
import {
PasswordGenerationServiceAbstraction,
UsernameGenerationServiceAbstraction,
} from "@bitwarden/generator-legacy";
import { CipherFormGenerationService } from "../abstractions/cipher-form-generation.service";
@Injectable()
export class DefaultCipherFormGenerationService implements CipherFormGenerationService {
constructor(
private passwordGenerationService: PasswordGenerationServiceAbstraction,
private usernameGenerationService: UsernameGenerationServiceAbstraction,
) {}
async generatePassword(): Promise<string> {
const [options] = await this.passwordGenerationService.getOptions();
return await this.passwordGenerationService.generatePassword(options);
}
async generateUsername(): Promise<string> {
const options = await this.usernameGenerationService.getOptions();
return await this.usernameGenerationService.generateUsername(options);
}
async generateInitialPassword(): Promise<string> {
return await this.generatePassword();
}
}