1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-04 10:43:47 +00:00

Improve Autofill IPC reliability (#14358)

* Delay IPC server start

* Better ipc handling

* Rename ready() to listenerReady()

---------

Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
This commit is contained in:
Anders Åberg
2025-05-13 14:16:33 +02:00
committed by GitHub
parent 28a94042f7
commit 4c5e396132
3 changed files with 55 additions and 5 deletions

View File

@@ -9,6 +9,8 @@ export default {
runCommand: <C extends Command>(params: RunCommandParams<C>): Promise<RunCommandResult<C>> =>
ipcRenderer.invoke("autofill.runCommand", params),
listenerReady: () => ipcRenderer.send("autofill.listenerReady"),
listenPasskeyRegistration: (
fn: (
clientId: number,

View File

@@ -296,6 +296,8 @@ export class DesktopAutofillService implements OnDestroy {
await this.adHocSync();
}
});
ipc.autofill.listenerReady();
}
private convertRegistrationRequest(

View File

@@ -7,6 +7,11 @@ import { WindowMain } from "../../../main/window.main";
import { CommandDefinition } from "./command";
type BufferedMessage = {
channel: string;
data: any;
};
export type RunCommandParams<C extends CommandDefinition> = {
namespace: C["namespace"];
command: C["name"];
@@ -17,12 +22,46 @@ export type RunCommandResult<C extends CommandDefinition> = C["output"];
export class NativeAutofillMain {
private ipcServer: autofill.IpcServer | null;
private messageBuffer: BufferedMessage[] = [];
private listenerReady = false;
constructor(
private logService: LogService,
private windowMain: WindowMain,
) {}
/**
* Safely sends a message to the renderer, buffering it if the server isn't ready yet
*/
private safeSend(channel: string, data: any) {
if (this.listenerReady && this.windowMain.win?.webContents) {
this.windowMain.win.webContents.send(channel, data);
} else {
this.logService.info(
`Buffering message to ${channel} until server is ready. Call .listenerReady() to flush.`,
);
this.messageBuffer.push({ channel, data });
}
}
/**
* Flushes all buffered messages to the renderer
*/
private flushMessageBuffer() {
if (!this.windowMain.win?.webContents) {
this.logService.error("Cannot flush message buffer - window not available");
return;
}
this.logService.info(`Flushing ${this.messageBuffer.length} buffered messages`);
for (const { channel, data } of this.messageBuffer) {
this.windowMain.win.webContents.send(channel, data);
}
this.messageBuffer = [];
}
async init() {
ipcMain.handle(
"autofill.runCommand",
@@ -43,7 +82,7 @@ export class NativeAutofillMain {
this.ipcServer.completeError(clientId, sequenceNumber, String(error));
return;
}
this.windowMain.win.webContents.send("autofill.passkeyRegistration", {
this.safeSend("autofill.passkeyRegistration", {
clientId,
sequenceNumber,
request,
@@ -56,7 +95,7 @@ export class NativeAutofillMain {
this.ipcServer.completeError(clientId, sequenceNumber, String(error));
return;
}
this.windowMain.win.webContents.send("autofill.passkeyAssertion", {
this.safeSend("autofill.passkeyAssertion", {
clientId,
sequenceNumber,
request,
@@ -69,7 +108,7 @@ export class NativeAutofillMain {
this.ipcServer.completeError(clientId, sequenceNumber, String(error));
return;
}
this.windowMain.win.webContents.send("autofill.passkeyAssertionWithoutUserInterface", {
this.safeSend("autofill.passkeyAssertionWithoutUserInterface", {
clientId,
sequenceNumber,
request,
@@ -82,8 +121,7 @@ export class NativeAutofillMain {
this.ipcServer.completeError(clientId, sequenceNumber, String(error));
return;
}
this.logService.info("Received native status", status);
this.windowMain.win.webContents.send("autofill.nativeStatus", {
this.safeSend("autofill.nativeStatus", {
clientId,
sequenceNumber,
status,
@@ -91,6 +129,14 @@ export class NativeAutofillMain {
},
);
ipcMain.on("autofill.listenerReady", async () => {
this.listenerReady = true;
this.logService.info(
`Listener is ready, flushing ${this.messageBuffer.length} buffered messages`,
);
this.flushMessageBuffer();
});
ipcMain.on("autofill.completePasskeyRegistration", (event, data) => {
this.logService.warning("autofill.completePasskeyRegistration", data);
const { clientId, sequenceNumber, response } = data;