From 78150d4efc4c5b1a24234e1c0971e30f73c1fbde Mon Sep 17 00:00:00 2001 From: Simon Pinfold Date: Mon, 19 Oct 2026 19:56:21 -0700 Subject: [PATCH 1/5] feat(bridge): expose per-install id to the hosted frontend (OBL-219) Add `getInstallId()` to the `__comfyDesktop2` bridge so the hosted ComfyUI frontend can read Desktop's per-installation id and send it to cloud as the `X-Comfy-Install-Id` header for request attribution (cloud#14451 reads it in the ingest WebSessionAuth guard). The value is the existing `getDeviceId()` installation id (SHA-256(machine_id + salt)): non-PII, stable per machine, already used for telemetry. No new id scheme. Exposed synchronously via `sendSync`, mirroring `isRemote`, so the frontend can read it inline when building request headers. Co-Authored-By: Claude Opus 4.8 --- .../comfyDesktopBridge.d.ts | 6 ++++ .../lib/ipc/registerDownloadHandlers.test.ts | 30 ++++++++++++++++++- src/main/lib/ipc/registerDownloadHandlers.ts | 8 +++++ src/preload/comfyPreload.ts | 1 + src/types/comfyDesktopBridge.ts | 6 ++++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/comfyui-desktop-bridge-types/comfyDesktopBridge.d.ts b/packages/comfyui-desktop-bridge-types/comfyDesktopBridge.d.ts index 8aa95ab0d..376412c25 100644 --- a/packages/comfyui-desktop-bridge-types/comfyDesktopBridge.d.ts +++ b/packages/comfyui-desktop-bridge-types/comfyDesktopBridge.d.ts @@ -168,6 +168,12 @@ export interface ComfyDesktop2Bridge { /** Reports whether the backend server is cloud/remote, not the user's location. * Optional: desktop builds predating it are still in the wild. */ isRemote?(): boolean + /** Returns the per-installation id: a non-PII, stable-per-machine value + * (`SHA-256(machine_id + salt)`, see main/lib/deviceId). The hosted + * frontend sends it to cloud as the `X-Comfy-Install-Id` header so cloud + * can attribute requests to a Desktop install. Not an identity/secret. + * Absent on Desktop builds predating it. */ + getInstallId?(): string openTerminal?: () => Promise openMcpSetup?: () => Promise /** Opens a model provider access page in the hosted frontend's browser session. diff --git a/src/main/lib/ipc/registerDownloadHandlers.test.ts b/src/main/lib/ipc/registerDownloadHandlers.test.ts index 1d928e5db..25ab1716b 100644 --- a/src/main/lib/ipc/registerDownloadHandlers.test.ts +++ b/src/main/lib/ipc/registerDownloadHandlers.test.ts @@ -6,7 +6,8 @@ const mocks = vi.hoisted(() => ({ handle: vi.fn(), on: vi.fn(), openModelAccessPageWindow: vi.fn(), - showItemInFolder: vi.fn() + showItemInFolder: vi.fn(), + getDeviceId: vi.fn() })) vi.mock('electron', () => ({ @@ -35,6 +36,10 @@ vi.mock('../modelAccessPage', () => ({ openModelAccessPageWindow: mocks.openModelAccessPageWindow })) +vi.mock('../deviceId', () => ({ + getDeviceId: mocks.getDeviceId +})) + import { registerDownloadHandlers } from './registerDownloadHandlers' type IpcHandler = ( @@ -66,3 +71,26 @@ describe('registerDownloadHandlers model access bridge', () => { expect(mocks.openModelAccessPageWindow).toHaveBeenCalledWith(sender, url) }) }) + +function onHandler(channel: string): (event: { returnValue?: unknown }) => void { + const call = mocks.on.mock.calls.find(([name]) => name === channel) + expect(call).toBeDefined() + return call![1] as (event: { returnValue?: unknown }) => void +} + +describe('registerDownloadHandlers install id bridge', () => { + beforeEach(() => { + vi.clearAllMocks() + registerDownloadHandlers() + }) + + it('answers the sync install-id request with getDeviceId()', () => { + mocks.getDeviceId.mockReturnValue('install-abc') + const event: { returnValue?: unknown } = {} + + onHandler('desktop2-get-install-id')(event) + + expect(event.returnValue).toBe('install-abc') + expect(mocks.getDeviceId).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/main/lib/ipc/registerDownloadHandlers.ts b/src/main/lib/ipc/registerDownloadHandlers.ts index b7cc716a9..825809cea 100644 --- a/src/main/lib/ipc/registerDownloadHandlers.ts +++ b/src/main/lib/ipc/registerDownloadHandlers.ts @@ -12,6 +12,7 @@ import { retryDownload, startModelDownload } from '../comfyDownloadManager' +import { getDeviceId } from '../deviceId' import { openModelAccessPageWindow } from '../modelAccessPage' export function registerDownloadHandlers(): void { @@ -20,6 +21,13 @@ export function registerDownloadHandlers(): void { event.returnValue = entry?.sourceCategory === 'cloud' || entry?.sourceCategory === 'remote' }) + // Per-installation id for cloud attribution (sent as X-Comfy-Install-Id by + // the hosted frontend). Synchronous so the frontend can read it inline when + // building request headers. getDeviceId() is safe post-initDeviceId(). + ipcMain.on('desktop2-get-install-id', (event) => { + event.returnValue = getDeviceId() + }) + ipcMain.handle('desktop2-open-model-access-page', (event, payload?: { url?: unknown }) => openModelAccessPageWindow(event.sender, payload?.url) ) diff --git a/src/preload/comfyPreload.ts b/src/preload/comfyPreload.ts index c3ee4a473..b7e8c21ed 100644 --- a/src/preload/comfyPreload.ts +++ b/src/preload/comfyPreload.ts @@ -323,6 +323,7 @@ const Auth: ComfyDesktop2AuthBridge = { const bridge = { isRemote: (): boolean => ipcRenderer.sendSync('desktop2-is-remote') as boolean, + getInstallId: (): string => ipcRenderer.sendSync('desktop2-get-install-id') as string, openModelAccessPage: (url: string): Promise => { return ipcRenderer.invoke('desktop2-open-model-access-page', { url }) }, diff --git a/src/types/comfyDesktopBridge.ts b/src/types/comfyDesktopBridge.ts index 8ee45aedc..dc227abe1 100644 --- a/src/types/comfyDesktopBridge.ts +++ b/src/types/comfyDesktopBridge.ts @@ -171,6 +171,12 @@ export interface ComfyDesktop2Bridge { /** Reports whether the backend server is cloud/remote, not the user's location. * Optional: desktop builds predating it are still in the wild. */ isRemote?(): boolean + /** Returns the per-installation id: a non-PII, stable-per-machine value + * (`SHA-256(machine_id + salt)`, see main/lib/deviceId). The hosted + * frontend sends it to cloud as the `X-Comfy-Install-Id` header so cloud + * can attribute requests to a Desktop install. Not an identity/secret. + * Absent on Desktop builds predating it. */ + getInstallId?(): string openTerminal?: () => Promise openMcpSetup?: () => Promise /** Opens a model provider access page in the hosted frontend's browser session. From c20447c14d99aabc09652361c686e631cb620b64 Mon Sep 17 00:00:00 2001 From: Simon Pinfold Date: Mon, 19 Oct 2026 21:29:42 -0700 Subject: [PATCH 2/5] chore(bridge-types): bump to 0.6.0 for the getInstallId addition The `getInstallId()` bridge member changes the published contract, so the "Bridge types version bumped" check requires a version bump. Minor bump: the member is additive and optional. Co-Authored-By: Claude Opus 4.8 --- packages/comfyui-desktop-bridge-types/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/comfyui-desktop-bridge-types/package.json b/packages/comfyui-desktop-bridge-types/package.json index d587b23c6..93c5e1d04 100644 --- a/packages/comfyui-desktop-bridge-types/package.json +++ b/packages/comfyui-desktop-bridge-types/package.json @@ -1,6 +1,6 @@ { "name": "@comfyorg/comfyui-desktop-bridge-types", - "version": "0.5.0", + "version": "0.6.0", "description": "TypeScript definitions for the Comfy Desktop hosted frontend bridge", "type": "module", "main": "./index.js", From b82bfaf0cba40de6ec2cf0e4bf0418f7938a4d0c Mon Sep 17 00:00:00 2001 From: Simon Pinfold Date: Tue, 20 Oct 2026 18:25:01 -0700 Subject: [PATCH 3/5] fix(bridge): only give the install id to cloud pages, and only a machine-derived one The sync handler now checks the sender's source category, so a user-configured remote server's page gets undefined, and withholds random/placeholder fallback ids, which change every launch. The preload memoises the first valid id so request building pays the sendSync once. getInstallId is typed string | undefined. --- .../comfyDesktopBridge.d.ts | 5 +- .../lib/ipc/registerDownloadHandlers.test.ts | 52 +++++++++++++++---- src/main/lib/ipc/registerDownloadHandlers.ts | 12 +++-- src/preload/comfyPreload.ts | 5 +- src/types/comfyDesktopBridge.ts | 5 +- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/packages/comfyui-desktop-bridge-types/comfyDesktopBridge.d.ts b/packages/comfyui-desktop-bridge-types/comfyDesktopBridge.d.ts index 376412c25..f2eb026af 100644 --- a/packages/comfyui-desktop-bridge-types/comfyDesktopBridge.d.ts +++ b/packages/comfyui-desktop-bridge-types/comfyDesktopBridge.d.ts @@ -172,8 +172,9 @@ export interface ComfyDesktop2Bridge { * (`SHA-256(machine_id + salt)`, see main/lib/deviceId). The hosted * frontend sends it to cloud as the `X-Comfy-Install-Id` header so cloud * can attribute requests to a Desktop install. Not an identity/secret. - * Absent on Desktop builds predating it. */ - getInstallId?(): string + * Undefined outside cloud-hosted pages or when the id is not + * machine-derived. Absent on Desktop builds predating it. */ + getInstallId?(): string | undefined openTerminal?: () => Promise openMcpSetup?: () => Promise /** Opens a model provider access page in the hosted frontend's browser session. diff --git a/src/main/lib/ipc/registerDownloadHandlers.test.ts b/src/main/lib/ipc/registerDownloadHandlers.test.ts index 25ab1716b..d64d87055 100644 --- a/src/main/lib/ipc/registerDownloadHandlers.test.ts +++ b/src/main/lib/ipc/registerDownloadHandlers.test.ts @@ -7,7 +7,8 @@ const mocks = vi.hoisted(() => ({ on: vi.fn(), openModelAccessPageWindow: vi.fn(), showItemInFolder: vi.fn(), - getDeviceId: vi.fn() + getDeviceId: vi.fn(), + getIdClass: vi.fn() })) vi.mock('electron', () => ({ @@ -37,7 +38,8 @@ vi.mock('../modelAccessPage', () => ({ })) vi.mock('../deviceId', () => ({ - getDeviceId: mocks.getDeviceId + getDeviceId: mocks.getDeviceId, + getIdClass: mocks.getIdClass })) import { registerDownloadHandlers } from './registerDownloadHandlers' @@ -72,10 +74,18 @@ describe('registerDownloadHandlers model access bridge', () => { }) }) -function onHandler(channel: string): (event: { returnValue?: unknown }) => void { +type SyncIpcEvent = { sender: unknown; returnValue?: unknown } + +function onHandler(channel: string): (event: SyncIpcEvent) => void { const call = mocks.on.mock.calls.find(([name]) => name === channel) expect(call).toBeDefined() - return call![1] as (event: { returnValue?: unknown }) => void + return call![1] as (event: SyncIpcEvent) => void +} + +function requestInstallId(): unknown { + const event: SyncIpcEvent = { sender: { id: 7 } } + onHandler('desktop2-get-install-id')(event) + return event.returnValue } describe('registerDownloadHandlers install id bridge', () => { @@ -84,13 +94,37 @@ describe('registerDownloadHandlers install id bridge', () => { registerDownloadHandlers() }) - it('answers the sync install-id request with getDeviceId()', () => { + it('answers a cloud page with the machine-derived id', () => { + mocks.findEntryByComfySender.mockReturnValue({ sourceCategory: 'cloud' }) + mocks.getIdClass.mockReturnValue('machine_derived') mocks.getDeviceId.mockReturnValue('install-abc') - const event: { returnValue?: unknown } = {} - onHandler('desktop2-get-install-id')(event) + expect(requestInstallId()).toBe('install-abc') + }) + + it.for(['remote', 'local', null])('withholds the id from a %s page', (sourceCategory) => { + mocks.findEntryByComfySender.mockReturnValue({ sourceCategory }) + mocks.getIdClass.mockReturnValue('machine_derived') + mocks.getDeviceId.mockReturnValue('install-abc') - expect(event.returnValue).toBe('install-abc') - expect(mocks.getDeviceId).toHaveBeenCalledTimes(1) + expect(requestInstallId()).toBeUndefined() }) + + it('withholds the id from an unregistered sender', () => { + mocks.findEntryByComfySender.mockReturnValue(null) + mocks.getIdClass.mockReturnValue('machine_derived') + + expect(requestInstallId()).toBeUndefined() + }) + + it.for(['random_fallback', 'placeholder_fallback'])( + 'withholds a %s id rather than sending one that changes every launch', + (idClass) => { + mocks.findEntryByComfySender.mockReturnValue({ sourceCategory: 'cloud' }) + mocks.getIdClass.mockReturnValue(idClass) + mocks.getDeviceId.mockReturnValue('random-per-launch') + + expect(requestInstallId()).toBeUndefined() + } + ) }) diff --git a/src/main/lib/ipc/registerDownloadHandlers.ts b/src/main/lib/ipc/registerDownloadHandlers.ts index 825809cea..b566dced4 100644 --- a/src/main/lib/ipc/registerDownloadHandlers.ts +++ b/src/main/lib/ipc/registerDownloadHandlers.ts @@ -12,7 +12,7 @@ import { retryDownload, startModelDownload } from '../comfyDownloadManager' -import { getDeviceId } from '../deviceId' +import { getDeviceId, getIdClass } from '../deviceId' import { openModelAccessPageWindow } from '../modelAccessPage' export function registerDownloadHandlers(): void { @@ -22,10 +22,14 @@ export function registerDownloadHandlers(): void { }) // Per-installation id for cloud attribution (sent as X-Comfy-Install-Id by - // the hosted frontend). Synchronous so the frontend can read it inline when - // building request headers. getDeviceId() is safe post-initDeviceId(). + // the cloud-hosted frontend). Only cloud pages get it, and only a + // machine-derived id: a fallback id changes every launch. ipcMain.on('desktop2-get-install-id', (event) => { - event.returnValue = getDeviceId() + const entry = findEntryByComfySender(event.sender) + event.returnValue = + entry?.sourceCategory === 'cloud' && getIdClass() === 'machine_derived' + ? getDeviceId() + : undefined }) ipcMain.handle('desktop2-open-model-access-page', (event, payload?: { url?: unknown }) => diff --git a/src/preload/comfyPreload.ts b/src/preload/comfyPreload.ts index b7e8c21ed..a9dbaeaf2 100644 --- a/src/preload/comfyPreload.ts +++ b/src/preload/comfyPreload.ts @@ -321,9 +321,12 @@ const Auth: ComfyDesktop2AuthBridge = { } } +let installId: string | undefined + const bridge = { isRemote: (): boolean => ipcRenderer.sendSync('desktop2-is-remote') as boolean, - getInstallId: (): string => ipcRenderer.sendSync('desktop2-get-install-id') as string, + getInstallId: (): string | undefined => + (installId ??= ipcRenderer.sendSync('desktop2-get-install-id') as string | undefined), openModelAccessPage: (url: string): Promise => { return ipcRenderer.invoke('desktop2-open-model-access-page', { url }) }, diff --git a/src/types/comfyDesktopBridge.ts b/src/types/comfyDesktopBridge.ts index dc227abe1..f8782b36d 100644 --- a/src/types/comfyDesktopBridge.ts +++ b/src/types/comfyDesktopBridge.ts @@ -175,8 +175,9 @@ export interface ComfyDesktop2Bridge { * (`SHA-256(machine_id + salt)`, see main/lib/deviceId). The hosted * frontend sends it to cloud as the `X-Comfy-Install-Id` header so cloud * can attribute requests to a Desktop install. Not an identity/secret. - * Absent on Desktop builds predating it. */ - getInstallId?(): string + * Undefined outside cloud-hosted pages or when the id is not + * machine-derived. Absent on Desktop builds predating it. */ + getInstallId?(): string | undefined openTerminal?: () => Promise openMcpSetup?: () => Promise /** Opens a model provider access page in the hosted frontend's browser session. From 78b0b61ebf9c3a0aa099bd5d8fb8c573a8b19223 Mon Sep 17 00:00:00 2001 From: Simon Pinfold Date: Tue, 20 Oct 2026 18:35:02 -0700 Subject: [PATCH 4/5] fix(bridge): require a trusted-cloud main frame for the install id A cloud view's registry category does not change if it navigates away, so also require the sender's URL to pass isTrustedCloudUrl (the policy the auth bridge already uses) and the request to come from its main frame. --- .../lib/ipc/registerDownloadHandlers.test.ts | 28 +++++++++++++++++-- src/main/lib/ipc/registerDownloadHandlers.ts | 19 +++++++++---- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/main/lib/ipc/registerDownloadHandlers.test.ts b/src/main/lib/ipc/registerDownloadHandlers.test.ts index d64d87055..b0edd739e 100644 --- a/src/main/lib/ipc/registerDownloadHandlers.test.ts +++ b/src/main/lib/ipc/registerDownloadHandlers.test.ts @@ -74,7 +74,9 @@ describe('registerDownloadHandlers model access bridge', () => { }) }) -type SyncIpcEvent = { sender: unknown; returnValue?: unknown } +type SyncIpcEvent = { sender: unknown; senderFrame: unknown; returnValue?: unknown } + +const CLOUD_URL = 'https://cloud.comfy.org/' function onHandler(channel: string): (event: SyncIpcEvent) => void { const call = mocks.on.mock.calls.find(([name]) => name === channel) @@ -82,8 +84,12 @@ function onHandler(channel: string): (event: SyncIpcEvent) => void { return call![1] as (event: SyncIpcEvent) => void } -function requestInstallId(): unknown { - const event: SyncIpcEvent = { sender: { id: 7 } } +function requestInstallId({ url = CLOUD_URL, fromSubframe = false } = {}): unknown { + const mainFrame = { name: 'main' } + const event: SyncIpcEvent = { + sender: { id: 7, mainFrame, getURL: () => url }, + senderFrame: fromSubframe ? { name: 'child' } : mainFrame + } onHandler('desktop2-get-install-id')(event) return event.returnValue } @@ -110,6 +116,22 @@ describe('registerDownloadHandlers install id bridge', () => { expect(requestInstallId()).toBeUndefined() }) + it('withholds the id once a cloud view has navigated off the trusted cloud origin', () => { + mocks.findEntryByComfySender.mockReturnValue({ sourceCategory: 'cloud' }) + mocks.getIdClass.mockReturnValue('machine_derived') + mocks.getDeviceId.mockReturnValue('install-abc') + + expect(requestInstallId({ url: 'https://example.com/' })).toBeUndefined() + }) + + it('withholds the id from a subframe of a cloud page', () => { + mocks.findEntryByComfySender.mockReturnValue({ sourceCategory: 'cloud' }) + mocks.getIdClass.mockReturnValue('machine_derived') + mocks.getDeviceId.mockReturnValue('install-abc') + + expect(requestInstallId({ fromSubframe: true })).toBeUndefined() + }) + it('withholds the id from an unregistered sender', () => { mocks.findEntryByComfySender.mockReturnValue(null) mocks.getIdClass.mockReturnValue('machine_derived') diff --git a/src/main/lib/ipc/registerDownloadHandlers.ts b/src/main/lib/ipc/registerDownloadHandlers.ts index b566dced4..2f61d1d76 100644 --- a/src/main/lib/ipc/registerDownloadHandlers.ts +++ b/src/main/lib/ipc/registerDownloadHandlers.ts @@ -1,4 +1,5 @@ import { BrowserWindow, ipcMain, shell } from 'electron' +import type { IpcMainEvent } from 'electron' import path from 'path' import { findEntryByComfySender } from '../../host/registry' import { @@ -14,6 +15,15 @@ import { } from '../comfyDownloadManager' import { getDeviceId, getIdClass } from '../deviceId' import { openModelAccessPageWindow } from '../modelAccessPage' +import { isTrustedCloudUrl } from '../trustedCloudUrl' + +function isTrustedCloudSender(event: IpcMainEvent): boolean { + return ( + findEntryByComfySender(event.sender)?.sourceCategory === 'cloud' && + event.senderFrame === event.sender.mainFrame && + isTrustedCloudUrl(event.sender.getURL()) + ) +} export function registerDownloadHandlers(): void { ipcMain.on('desktop2-is-remote', (event) => { @@ -22,14 +32,11 @@ export function registerDownloadHandlers(): void { }) // Per-installation id for cloud attribution (sent as X-Comfy-Install-Id by - // the cloud-hosted frontend). Only cloud pages get it, and only a - // machine-derived id: a fallback id changes every launch. + // the cloud-hosted frontend). Only the main frame of a trusted cloud page + // gets it, and only a machine-derived id: a fallback id changes every launch. ipcMain.on('desktop2-get-install-id', (event) => { - const entry = findEntryByComfySender(event.sender) event.returnValue = - entry?.sourceCategory === 'cloud' && getIdClass() === 'machine_derived' - ? getDeviceId() - : undefined + isTrustedCloudSender(event) && getIdClass() === 'machine_derived' ? getDeviceId() : undefined }) ipcMain.handle('desktop2-open-model-access-page', (event, payload?: { url?: unknown }) => From 13813076ff4e3ef1073f269301e120cf2c8e1bfe Mon Sep 17 00:00:00 2001 From: Simon Pinfold Date: Wed, 21 Oct 2026 08:09:34 -0700 Subject: [PATCH 5/5] fix(bridge): compare the install-id sender frame by process and routing id WebFrameMain instances for the same frame need not be the same object, so identity comparison could reject the cloud page's own main frame and the header would silently never be sent. Match frames by processId/routingId, as isTrustedSender and firebaseAuthReporterFrame already do, reject a missing senderFrame, and check the frame's own URL. --- .../lib/ipc/registerDownloadHandlers.test.ts | 25 +++++++++++++++---- src/main/lib/ipc/registerDownloadHandlers.ts | 10 +++++--- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/main/lib/ipc/registerDownloadHandlers.test.ts b/src/main/lib/ipc/registerDownloadHandlers.test.ts index b0edd739e..613286124 100644 --- a/src/main/lib/ipc/registerDownloadHandlers.test.ts +++ b/src/main/lib/ipc/registerDownloadHandlers.test.ts @@ -84,11 +84,18 @@ function onHandler(channel: string): (event: SyncIpcEvent) => void { return call![1] as (event: SyncIpcEvent) => void } -function requestInstallId({ url = CLOUD_URL, fromSubframe = false } = {}): unknown { - const mainFrame = { name: 'main' } +type FrameShape = 'main' | 'subframe' | 'missing' + +function requestInstallId({ url = CLOUD_URL, frame = 'main' as FrameShape } = {}): unknown { + const mainFrame = { processId: 3, routingId: 1, url } + const senderFrames = { + main: { processId: 3, routingId: 1, url }, + subframe: { processId: 3, routingId: 2, url }, + missing: null + } const event: SyncIpcEvent = { - sender: { id: 7, mainFrame, getURL: () => url }, - senderFrame: fromSubframe ? { name: 'child' } : mainFrame + sender: { id: 7, mainFrame }, + senderFrame: senderFrames[frame] } onHandler('desktop2-get-install-id')(event) return event.returnValue @@ -129,7 +136,15 @@ describe('registerDownloadHandlers install id bridge', () => { mocks.getIdClass.mockReturnValue('machine_derived') mocks.getDeviceId.mockReturnValue('install-abc') - expect(requestInstallId({ fromSubframe: true })).toBeUndefined() + expect(requestInstallId({ frame: 'subframe' })).toBeUndefined() + }) + + it('withholds the id when the sending frame is gone', () => { + mocks.findEntryByComfySender.mockReturnValue({ sourceCategory: 'cloud' }) + mocks.getIdClass.mockReturnValue('machine_derived') + mocks.getDeviceId.mockReturnValue('install-abc') + + expect(requestInstallId({ frame: 'missing' })).toBeUndefined() }) it('withholds the id from an unregistered sender', () => { diff --git a/src/main/lib/ipc/registerDownloadHandlers.ts b/src/main/lib/ipc/registerDownloadHandlers.ts index 2f61d1d76..8428a1c49 100644 --- a/src/main/lib/ipc/registerDownloadHandlers.ts +++ b/src/main/lib/ipc/registerDownloadHandlers.ts @@ -17,11 +17,13 @@ import { getDeviceId, getIdClass } from '../deviceId' import { openModelAccessPageWindow } from '../modelAccessPage' import { isTrustedCloudUrl } from '../trustedCloudUrl' -function isTrustedCloudSender(event: IpcMainEvent): boolean { +function isTrustedCloudSender({ sender, senderFrame }: IpcMainEvent): boolean { + if (findEntryByComfySender(sender)?.sourceCategory !== 'cloud' || !senderFrame) return false + const mainFrame = sender.mainFrame return ( - findEntryByComfySender(event.sender)?.sourceCategory === 'cloud' && - event.senderFrame === event.sender.mainFrame && - isTrustedCloudUrl(event.sender.getURL()) + senderFrame.processId === mainFrame.processId && + senderFrame.routingId === mainFrame.routingId && + isTrustedCloudUrl(senderFrame.url) ) }