收紧媒体导出载荷边界
将图片和音频导出载荷预校验提升到共享 HostBridge 契约 让 H5 facade 按共享媒体导出边界归一化文件名、MIME 和 base64 载荷 保留 Expo 与 Tauri 壳对真实字节和 MIME 的二次校验 增加媒体导出载荷测试和三端壳总门禁反查 同步宿主壳协议文档和共享决策记录
This commit is contained in:
@@ -1053,8 +1053,8 @@ describe('hostBridge', () => {
|
||||
).resolves.toBe(false);
|
||||
await expect(
|
||||
exportHostImageFile({
|
||||
fileName: '分享卡.png',
|
||||
base64Data: 'c2hhcmUtY2FyZA==',
|
||||
fileName: ' ../分享:卡?.png ',
|
||||
base64Data: ' c2hhcmUtY2FyZA== ',
|
||||
mimeType: 'image/png',
|
||||
}),
|
||||
).resolves.toBe(true);
|
||||
@@ -1220,7 +1220,7 @@ describe('hostBridge', () => {
|
||||
request: expect.objectContaining({
|
||||
method: 'file.exportImage',
|
||||
payload: {
|
||||
fileName: '分享卡.png',
|
||||
fileName: '分享-卡-.png',
|
||||
base64Data: 'c2hhcmUtY2FyZA==',
|
||||
mimeType: 'image/png',
|
||||
},
|
||||
@@ -1536,6 +1536,16 @@ describe('hostBridge', () => {
|
||||
timeoutMs: HOST_BRIDGE_USER_INTERACTION_TIMEOUT_MS,
|
||||
}),
|
||||
});
|
||||
|
||||
invoke.mockClear();
|
||||
await expect(
|
||||
exportHostImageFile({
|
||||
fileName: 'bad.gif',
|
||||
base64Data: 'c2hhcmUtY2FyZA==',
|
||||
mimeType: 'image/gif' as 'image/png',
|
||||
}),
|
||||
).resolves.toBe(false);
|
||||
expect(invoke).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('原生 App 宿主不支持文本导出时回退 H5', async () => {
|
||||
@@ -1897,6 +1907,16 @@ describe('hostBridge', () => {
|
||||
timeoutMs: HOST_BRIDGE_USER_INTERACTION_TIMEOUT_MS,
|
||||
}),
|
||||
});
|
||||
|
||||
invoke.mockClear();
|
||||
await expect(
|
||||
exportHostAudioFile({
|
||||
fileName: 'empty.wav',
|
||||
base64Data: ' ',
|
||||
mimeType: 'audio/wav',
|
||||
}),
|
||||
).resolves.toBe(false);
|
||||
expect(invoke).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('原生 App 宿主取消导入音频时回退为 false', async () => {
|
||||
|
||||
@@ -43,6 +43,8 @@ import {
|
||||
normalizeHostBridgeClipboardText,
|
||||
normalizeHostBridgeColorScheme,
|
||||
normalizeHostBridgeConnectionType,
|
||||
normalizeHostBridgeExportAudioPayload,
|
||||
normalizeHostBridgeExportImagePayload,
|
||||
normalizeHostBridgeExternalUrlPayload,
|
||||
normalizeHostBridgeHapticsImpactStyle,
|
||||
normalizeHostBridgeLifecycleState,
|
||||
@@ -854,10 +856,15 @@ export async function exportHostImageFile(
|
||||
return false;
|
||||
}
|
||||
|
||||
const normalizedPayload = normalizeHostBridgeExportImagePayload(params);
|
||||
if (!normalizedPayload) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return await requestNativeAppHostBridge<FileExportImageResult>(
|
||||
'file.exportImage',
|
||||
params,
|
||||
normalizedPayload,
|
||||
{ timeoutMs: HOST_BRIDGE_USER_INTERACTION_TIMEOUT_MS },
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -875,10 +882,15 @@ export async function exportHostAudioFile(
|
||||
return false;
|
||||
}
|
||||
|
||||
const normalizedPayload = normalizeHostBridgeExportAudioPayload(params);
|
||||
if (!normalizedPayload) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return await requestNativeAppHostBridge<FileExportAudioResult>(
|
||||
'file.exportAudio',
|
||||
params,
|
||||
normalizedPayload,
|
||||
{ timeoutMs: HOST_BRIDGE_USER_INTERACTION_TIMEOUT_MS },
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user