feat(templates):新增 Markdown 内容页支持
新增 template: content:构建期使用 markdown-it 将本地Markdown 渲染为 HTML(禁用 raw HTML/图片),并按MeNav的URLscheme白名单策略对链接做安全降级
This commit is contained in:
91
test/content-page-markdown.node-test.js
Normal file
91
test/content-page-markdown.node-test.js
Normal file
@@ -0,0 +1,91 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
|
||||
const { loadHandlebarsTemplates, generateAllPagesHTML } = require('../src/generator.js');
|
||||
|
||||
function withRepoRoot(fn) {
|
||||
const originalCwd = process.cwd();
|
||||
process.chdir(path.join(__dirname, '..'));
|
||||
try {
|
||||
return fn();
|
||||
} finally {
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
}
|
||||
|
||||
test('content:构建期渲染 markdown 文件,并对链接做 scheme 安全降级', () => {
|
||||
withRepoRoot(() => {
|
||||
loadHandlebarsTemplates();
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'menav-content-page-'));
|
||||
const mdPath = path.join(tmpDir, 'about.md');
|
||||
fs.writeFileSync(
|
||||
mdPath,
|
||||
[
|
||||
'# About',
|
||||
'',
|
||||
'A normal link: [ok](https://example.com)',
|
||||
'',
|
||||
'A bad link: [bad](javascript:alert(1))',
|
||||
'',
|
||||
'Protocol-relative should be blocked: [pr](//example.com)',
|
||||
'',
|
||||
'Image should be disabled: ',
|
||||
].join('\n'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
try {
|
||||
const config = {
|
||||
site: {
|
||||
title: 'Test Site',
|
||||
description: '',
|
||||
author: '',
|
||||
favicon: '',
|
||||
logo_text: 'Test',
|
||||
security: { allowedSchemes: ['http', 'https', 'mailto', 'tel'] },
|
||||
},
|
||||
profile: { title: 'PROFILE_TITLE', subtitle: 'PROFILE_SUBTITLE' },
|
||||
social: [],
|
||||
navigation: [{ id: 'about', name: '关于', icon: 'fas fa-info' }],
|
||||
about: {
|
||||
title: '关于',
|
||||
subtitle: '说明',
|
||||
template: 'content',
|
||||
content: {
|
||||
file: mdPath,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const pages = generateAllPagesHTML(config);
|
||||
const html = pages.about;
|
||||
|
||||
assert.ok(typeof html === 'string' && html.length > 0);
|
||||
assert.ok(html.includes('page-template-about'));
|
||||
assert.ok(html.includes('page-template-content'));
|
||||
assert.ok(html.includes('<h1>About</h1>'));
|
||||
assert.ok(html.includes('A normal link'));
|
||||
assert.ok(html.includes('href="https://example.com"'));
|
||||
|
||||
// javascript: should be blocked
|
||||
assert.ok(html.includes('A bad link'));
|
||||
assert.ok(/href=['"]#['"]/.test(html), '不安全链接应降级为 href="#"');
|
||||
|
||||
// protocol-relative should be blocked
|
||||
assert.ok(html.includes('Protocol-relative should be blocked'));
|
||||
|
||||
// image should be disabled
|
||||
assert.ok(!html.includes('<img'), '本期不支持图片:markdown 渲染不应输出 <img>');
|
||||
} finally {
|
||||
try {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user