From 7c6bf03f5778bc29f578fff537a57a49bf43a37a Mon Sep 17 00:00:00 2001 From: Miles Blackwood Date: Fri, 23 Jan 2026 11:34:06 -0500 Subject: [PATCH] Ensure imperative accessor continuity. --- .../autofill/background/overlay.background.ts | 26 ++++++++++++++----- .../browser/src/background/main.background.ts | 16 +++++------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index a1e8c26f0ea..7feaf793fa2 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -9,6 +9,7 @@ import { ReplaySubject, Subject, switchMap, + tap, throttleTime, } from "rxjs"; import { parse } from "tldts"; @@ -48,7 +49,7 @@ import { Fido2CredentialView } from "@bitwarden/common/vault/models/view/fido2-c import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; -import { GenerateRequest } from "@bitwarden/generator-core"; +import { GenerateRequest, Type } from "@bitwarden/generator-core"; import { GeneratedCredential } from "@bitwarden/generator-history"; // FIXME (PM-22628): Popup imports are forbidden in background @@ -124,6 +125,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { private readonly repositionInlineMenu$ = new Subject(); private readonly rebuildSubFrameOffsets$ = new Subject(); private readonly addNewVaultItem$ = new Subject(); + private readonly requestGeneratedPassword$ = new Subject(); private pageDetailsForTab: PageDetailsForTab = {}; private subFrameOffsetsForTab: SubFrameOffsetsForTab = {}; private portKeyForTab: Record = {}; @@ -148,6 +150,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { private showPasskeysLabelsWithinInlineMenu: boolean = false; private iconsServerUrl: string; private generatedPassword: string; + private yieldedPassword$: Observable; private readonly validPortConnections: Set = new Set([ AutofillOverlayPort.Button, AutofillOverlayPort.ButtonMessageConnector, @@ -236,7 +239,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { private themeStateService: ThemeStateService, private totpService: TotpService, private accountService: AccountService, - private generatePasswordCallback: ( + private yieldGeneratedPassword: ( $on: Observable, ) => Observable, private addPasswordCallback: (password: string) => Promise, @@ -252,6 +255,15 @@ export class OverlayBackground implements OverlayBackgroundInterface { this.setupExtensionListeners(); const env = await firstValueFrom(this.environmentService.environment$); this.iconsServerUrl = env.getIconsUrl(); + this.yieldedPassword$ = this.yieldGeneratedPassword(merge(this.requestGeneratedPassword$)); + this.yieldedPassword$ + .pipe( + tap(async ({ credential }) => { + this.generatedPassword = credential; + await this.addPasswordCallback(this.generatedPassword); + }), + ) + .subscribe(); } /** @@ -1801,9 +1813,8 @@ export class OverlayBackground implements OverlayBackgroundInterface { /** * Generates a password based on the user defined password generation options. */ - private async generatePassword(): Promise { - this.generatedPassword = await this.generatePasswordCallback(); - await this.addPasswordCallback(this.generatedPassword); + private async requestGeneratedPassword(source: GenerateRequest["source"]) { + this.requestGeneratedPassword$.next({ source, type: Type.password }); } /** @@ -1813,7 +1824,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { */ private async updateGeneratedPassword(refreshPassword: boolean = false) { if (!this.generatedPassword || refreshPassword) { - await this.generatePassword(); + await this.requestGeneratedPassword("inline-menu"); } this.postMessageToPort(this.inlineMenuListPort, { @@ -2949,6 +2960,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { isInlineMenuListPort, showInlineMenuAccountCreation, ); + const showSaveLoginMenu = (await this.checkFocusedFieldHasValue(port.sender.tab)) && (await this.shouldShowSaveLoginInlineMenuList(port.sender.tab)); @@ -3077,7 +3089,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { } if (!this.generatedPassword) { - await this.generatePassword(); + await this.requestGeneratedPassword(); } return true; diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index b5e441c913e..ff10bfb826c 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -10,6 +10,7 @@ import { map, merge, Observable, + of, Subject, switchMap, timeout, @@ -222,14 +223,14 @@ import { SearchService } from "@bitwarden/common/vault/services/search.service"; import { TotpService } from "@bitwarden/common/vault/services/totp.service"; import { VaultSettingsService } from "@bitwarden/common/vault/services/vault-settings/vault-settings.service"; import { DefaultTaskService, TaskService } from "@bitwarden/common/vault/tasks"; +import { GenerateRequest, Type } from "@bitwarden/generator-core"; +import { GeneratedCredential } from "@bitwarden/generator-history"; import { legacyPasswordGenerationServiceFactory, legacyUsernameGenerationServiceFactory, PasswordGenerationServiceAbstraction, UsernameGenerationServiceAbstraction, } from "@bitwarden/generator-legacy"; -import { GenerateRequest } from "@bitwarden/generator-core"; -import { GeneratedCredential } from "@bitwarden/generator-history"; import { DefaultImportMetadataService, ImportApiService, @@ -2017,7 +2018,7 @@ export default class MainBackground { this.totpService, this.accountService, this.yieldGeneratedPassword, - (password) => this.addPasswordToHistory(password), + this.addPasswordToHistory, ); this.autofillBadgeUpdaterService = new AutofillBadgeUpdaterService( @@ -2059,13 +2060,10 @@ export default class MainBackground { ); }; - generatePassword = async (): Promise => { - const options = (await this.passwordGenerationService.getOptions())?.[0] ?? {}; - return await this.passwordGenerationService.generatePassword(options); - }; - generatePasswordToClipboard = async () => { - const password = await this.generatePassword(); + const { credential: password } = await firstValueFrom( + this.yieldGeneratedPassword(of({ source: "clipboard", type: Type.password })), + ); this.platformUtilsService.copyToClipboard(password); await this.addPasswordToHistory(password); };