收紧移动壳文本导出校验顺序
移动壳文本导出先校验 MIME 再探测原生分享能力 移动壳文件测试覆盖非法文本 MIME 不触碰原生分享 移动壳配置检查锁定文本导出本地校验顺序
This commit is contained in:
@@ -2104,6 +2104,20 @@ if (
|
||||
) {
|
||||
throw new Error('mobile shell image export must reject empty and oversized bytes');
|
||||
}
|
||||
const exportTextFileBody = extractFunctionBody(filesSource, 'exportTextFile');
|
||||
const exportTextMimeValidationIndex = exportTextFileBody.indexOf(
|
||||
'HOST_BRIDGE_TEXT_MIME_TYPE_SET.has(mimeType as HostBridgeTextMimeType)',
|
||||
);
|
||||
const exportTextSharingAvailabilityIndex = exportTextFileBody.indexOf(
|
||||
'await assertMobileFileSharingAvailable()',
|
||||
);
|
||||
if (
|
||||
exportTextMimeValidationIndex < 0 ||
|
||||
exportTextSharingAvailabilityIndex < 0 ||
|
||||
exportTextMimeValidationIndex > exportTextSharingAvailabilityIndex
|
||||
) {
|
||||
throw new Error('mobile shell text export must validate MIME before native sharing checks');
|
||||
}
|
||||
|
||||
for (const [wrapperName, fileCall] of [
|
||||
['exportMobileHostBridgeTextFile', 'ok(request, await exportTextFile(request.payload))'],
|
||||
@@ -2126,6 +2140,7 @@ for (const snippet of [
|
||||
'exportTextFile({',
|
||||
'exportImageFile({',
|
||||
'rejects every export before cache writes when system sharing is unavailable',
|
||||
'rejects invalid text export MIME before touching native sharing',
|
||||
'const exportCases = [',
|
||||
'expect(writtenFiles).toHaveLength(0)',
|
||||
'importTextFile()',
|
||||
|
||||
@@ -185,6 +185,23 @@ describe('mobile HostBridge file actions', () => {
|
||||
expect(shareAsyncMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('rejects invalid text export MIME before touching native sharing', async () => {
|
||||
await expect(
|
||||
exportTextFile({
|
||||
content: '泥巴AI',
|
||||
fileName: '创作记录',
|
||||
mimeType: 'application/octet-stream',
|
||||
}),
|
||||
).rejects.toMatchObject({
|
||||
code: 'invalid_request',
|
||||
message: 'mimeType must be an allowed text type',
|
||||
});
|
||||
|
||||
expect(shareAvailableMock).not.toHaveBeenCalled();
|
||||
expect(writtenFiles).toHaveLength(0);
|
||||
expect(shareAsyncMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('maps native sharing availability failures to stable export errors', async () => {
|
||||
shareAvailableMock.mockRejectedValueOnce(new Error('expo sharing crashed'));
|
||||
|
||||
|
||||
@@ -109,8 +109,6 @@ export async function exportTextFile(
|
||||
throw invalidRequest('content exceeds file export size limit');
|
||||
}
|
||||
|
||||
await assertMobileFileSharingAvailable();
|
||||
|
||||
const fileName = normalizeHostBridgeExportFileName(exportPayload?.fileName);
|
||||
const rawMimeType = exportPayload?.mimeType;
|
||||
const mimeType =
|
||||
@@ -120,6 +118,9 @@ export async function exportTextFile(
|
||||
if (!HOST_BRIDGE_TEXT_MIME_TYPE_SET.has(mimeType as HostBridgeTextMimeType)) {
|
||||
throw invalidRequest('mimeType must be an allowed text type');
|
||||
}
|
||||
|
||||
await assertMobileFileSharingAvailable();
|
||||
|
||||
try {
|
||||
const file = new File(Paths.cache, fileName);
|
||||
file.write(content);
|
||||
|
||||
Reference in New Issue
Block a user