diff --git a/mindspace-content-scan.mjs b/mindspace-content-scan.mjs index 5474dd2..46b95c7 100644 --- a/mindspace-content-scan.mjs +++ b/mindspace-content-scan.mjs @@ -92,6 +92,15 @@ const HTML_RULES = [ mask: () => '', replacement: () => '', }, + { + type: 'html_external_script', + label: '外部 CDN 脚本', + riskLevel: 'high', + blocking: true, + pattern: /', + { format: 'html', allowHtmlActiveContent: true }, + ); + assert.equal(result.allowed, false); + assert.ok(result.findings.some((finding) => finding.type === 'html_external_script' && finding.blocking)); +}); + +test('scanContent allows same-origin script src with active html content', () => { + const result = scanContent( + '', + { format: 'html', allowHtmlActiveContent: true }, + ); + assert.equal(result.allowed, true); + assert.ok(!result.findings.some((finding) => finding.type === 'html_external_script')); +}); + test('redactContent masks secrets and strips unsafe html', () => { const result = redactContent( '手机号 13800138000\n邮箱 john@example.com\n\nkey=sk_test_1234567890abcdef', diff --git a/mindspace-publications.mjs b/mindspace-publications.mjs index d34964f..6ecc79a 100644 --- a/mindspace-publications.mjs +++ b/mindspace-publications.mjs @@ -2,6 +2,7 @@ import crypto from 'node:crypto'; import fs from 'node:fs/promises'; import path from 'node:path'; import { localizeGoogleFontsCss } from './mindspace-html-localize.mjs'; +import { rewriteKnownCdnScriptSources } from './mindspace-published-script-localize.mjs'; import { replacePrivateResourceReferences, scanContent } from './mindspace-content-scan.mjs'; import { pageInternals, normalizeWorkspaceRelativePath } from './mindspace-pages.mjs'; import { readWorkspacePublishHtml } from './mindspace-workspace-path.mjs'; @@ -352,6 +353,7 @@ async function prepareHtmlPublishContent({ h5Root = null, }) { let publishContent = (await localizeGoogleFontsCss(html)).html; + publishContent = rewriteKnownCdnScriptSources(publishContent).html; publishContent = replaceImgproxyStandardImageReferences( publishContent, resolvePublicBaseUrl(), diff --git a/mindspace-publications.test.mjs b/mindspace-publications.test.mjs index ff0a291..5122d5e 100644 --- a/mindspace-publications.test.mjs +++ b/mindspace-publications.test.mjs @@ -709,6 +709,27 @@ test('prepareHtmlPublishContent rewrites workspace public asset paths relative t assert.doesNotMatch(prepared, /"cover":"public\//); }); +test('prepareHtmlPublishContent rewrites known chart.js cdn scripts to platform asset', async () => { + const prepared = await publicationInternals.prepareHtmlPublishContent({ + pool: { + async query() { + return [[]]; + }, + }, + userId: 'user-1', + html: '