diff --git a/scripts/check-native-shells.mjs b/scripts/check-native-shells.mjs index 2552b7655..172eb2c89 100644 --- a/scripts/check-native-shells.mjs +++ b/scripts/check-native-shells.mjs @@ -1093,6 +1093,17 @@ function assertH5HostBridgePayloadBoundaries() { 'H5 HostBridge facade must normalize share.open payloads with the shared share boundary', ); } + if ( + !h5HostBridgeSource.includes( + 'const normalizedPayload = normalizeHostBridgeShareOpenPayload(message);', + ) || + !h5HostBridgeSource.includes("normalizedPayload.status !== 'valid'") || + !h5HostBridgeSource.includes("'share.setTarget', {\n target: message,") + ) { + throw new Error( + 'H5 HostBridge facade must validate native share.setTarget payloads before sending them to native shells', + ); + } if ( !h5HostBridgeSource.includes( 'const normalizedPayload = normalizeHostBridgeExportTextPayload(params);', diff --git a/src/services/host-bridge/hostBridge.test.ts b/src/services/host-bridge/hostBridge.test.ts index 0b5c59364..2a829f3ac 100644 --- a/src/services/host-bridge/hostBridge.test.ts +++ b/src/services/host-bridge/hostBridge.test.ts @@ -878,6 +878,47 @@ describe('hostBridge', () => { expect(setHostShareTarget({ type: 'test' })).toBe(false); }); + test('原生 App 宿主分享目标同步前先拒绝无效目标', () => { + const invoke = vi.fn(); + window.history.replaceState( + null, + '', + nativeAppPath(['share.setTarget']), + ); + window.__TAURI__ = { + core: { + invoke: asTauriInvoke(invoke), + }, + }; + + expect(setHostShareTarget({})).toBe(false); + expect( + setHostShareTarget({ + title: '危险作品', + url: 'https://example.com/works/detail?work=PZ-1', + }), + ).toBe(false); + expect(invoke).not.toHaveBeenCalled(); + + expect( + setHostShareTarget({ + title: '暖灯猫街', + work: 'PZ-00000001', + }), + ).toBe(true); + expect(invoke).toHaveBeenCalledWith('host_bridge_request', { + request: expect.objectContaining({ + method: 'share.setTarget', + payload: { + target: { + title: '暖灯猫街', + work: 'PZ-00000001', + }, + }, + }), + }); + }); + test('原生 App 宿主通过 HostBridge 处理导航、登录和支付', async () => { const invoke = vi.fn(async (_command: string, args?: Record) => { const request = (args as { request: { id: string; method: string } }) diff --git a/src/services/host-bridge/hostBridge.ts b/src/services/host-bridge/hostBridge.ts index 9fc9a180c..54eebcaff 100644 --- a/src/services/host-bridge/hostBridge.ts +++ b/src/services/host-bridge/hostBridge.ts @@ -699,6 +699,10 @@ export function setHostShareTarget(message: unknown) { if (!canUseNativeHostCapability('share.setTarget')) { return false; } + const normalizedPayload = normalizeHostBridgeShareOpenPayload(message); + if (normalizedPayload.status !== 'valid') { + return false; + } void requestNativeAppHostBridge('share.setTarget', { target: message, }).catch(() => {