Files
menav/test/content-page-markdown.node-test.js
rbetree 280d376bac feat(templates):新增 Markdown 内容页支持
新增 template: content:构建期使用 markdown-it 将本地Markdown 渲染为 HTML(禁用 raw HTML/图片),并按MeNav的URLscheme白名单策略对链接做安全降级
2026-01-20 18:23:32 +08:00

92 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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: ![x](https://example.com/x.png)',
].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
}
}
});
});