Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(post): avoid swig in code being double escaped #4362

Merged
merged 1 commit into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions lib/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const { slugize, escapeRegExp } = require('hexo-util');
const { copyDir, exists, listDir, mkdirs, readFile, rmdir, unlink, writeFile } = require('hexo-fs');
const yfm = require('hexo-front-matter');

const replaceSwigTag = str => str.replace(/{/g, '\uFFFCleft\uFFFC').replace(/}/g, '\uFFFCright\uFFFC');
const restoreReplacesSwigTag = str => str.replace(/\uFFFCleft\uFFFC/g, '{').replace(/\uFFFCright\uFFFC/g, '}');

const preservedKeys = ['title', 'slug', 'path', 'layout', 'date', 'content'];

const rPlaceholder = /(?:<|&lt;)!--\uFFFC(\d+)--(?:>|&gt;)/g;
Expand All @@ -18,7 +21,7 @@ const rSwigComment = /\{#[\s\S]*?#\}/g;
const rSwigBlock = /\{%[\s\S]*?%\}/g;
const rSwigFullBlock = /\{% *(.+?)(?: *| +.*?)%\}[\s\S]+?\{% *end\1 *%\}/g;
const rSwigRawFullBlock = /{% *raw *%\}[\s\S]+?\{% *endraw *%\}/g;
const rSwigTagInsideInlineCode = /`.*{.*}.*`/g;
const rSwigTagInsideInlineCode = /`.*?{.*?}.*?`/g;

const _escapeContent = (cache, str) => {
const placeholder = '\uFFFC';
Expand Down Expand Up @@ -48,9 +51,7 @@ class PostRenderCache {
escapeAllSwigTags(str) {
const escape = _str => _escapeContent(this.cache, _str);
return str.replace(rSwigRawFullBlock, escape) // Escape {% raw %} first
.replace(rSwigTagInsideInlineCode, str => {
return str.replace(/{/g, '&#123;').replace(/}/g, '&#125;');
})
.replace(rSwigTagInsideInlineCode, replaceSwigTag) // Avoid double escaped by marked renderer
.replace(rSwigFullBlock, escape)
.replace(rSwigBlock, escape)
.replace(rSwigComment, '')
Expand Down Expand Up @@ -256,7 +257,6 @@ class Post {

return promise.then(content => {
data.content = content;

// Run "before_post_render" filters
return ctx.execFilter('before_post_render', data, { context: ctx });
}).then(() => {
Expand All @@ -277,7 +277,7 @@ class Post {
toString: true,
onRenderEnd(content) {
// Replace cache data with real contents
data.content = cacheObj.loadContent(content);
data.content = cacheObj.loadContent(restoreReplacesSwigTag(content));

// Return content after replace the placeholders
if (disableNunjucks) return data.content;
Expand All @@ -287,6 +287,7 @@ class Post {
}
}, options);
}).then(content => {
// restore { and } inside inline code
data.content = content;

// Run "after_post_render" filters
Expand Down
42 changes: 36 additions & 6 deletions test/scripts/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { highlight, escapeHTML } = require('hexo-util');
const { spy, useFakeTimers } = require('sinon');
const frontMatter = require('hexo-front-matter');
const fixture = require('../../fixtures/post_render');
const escapeSwigTag = str => str.replace(/{/g, '&#123;').replace(/}/g, '&#125;');

describe('Post', () => {
const Hexo = require('../../../lib/hexo');
Expand Down Expand Up @@ -455,8 +456,8 @@ describe('Post', () => {
const paths = [join(hexo.source_dir, '_posts', 'Hello-World-1.md')];

return Promise.all([
post.create({title: 'Hello World', layout: 'draft'}),
post.create({title: 'Hello World'})
post.create({ title: 'Hello World', layout: 'draft' }),
post.create({ title: 'Hello World' })
]).then(data => {
paths.push(data[1].path);

Expand All @@ -473,8 +474,8 @@ describe('Post', () => {
const path = join(hexo.source_dir, '_posts', 'Hello-World.md');

return Promise.all([
post.create({title: 'Hello World', layout: 'draft'}),
post.create({title: 'Hello World'})
post.create({ title: 'Hello World', layout: 'draft' }),
post.create({ title: 'Hello World' })
]).then(data => post.publish({
slug: 'Hello-World'
}, true)).then(data => {
Expand Down Expand Up @@ -1015,7 +1016,7 @@ describe('Post', () => {
engine: 'markdown'
});

data.content.trim().should.eql('<p>In Go’s templates, blocks look like this: <code>&amp;#123;&amp;#123;block &quot;template name&quot; .&amp;#125;&amp;#125; (content) &amp;#123;&amp;#123;end&amp;#125;&amp;#125;</code>.</p>');
data.content.trim().should.eql(`<p>In Go’s templates, blocks look like this: <code>${escapeSwigTag(escapeHTML('{{block "template name" .}} (content) {{end}}'))}</code>.</p>`);
});

// test for https://github.com/hexojs/hexo/issues/3346#issuecomment-595497849
Expand All @@ -1027,7 +1028,7 @@ describe('Post', () => {
engine: 'markdown'
});

data.content.trim().should.eql('<p><code>&amp;#123;&amp;#123; 1 + 1 &amp;#125;&amp;#125;</code> 2</p>');
data.content.trim().should.eql(`<p><code>${escapeSwigTag('{{ 1 + 1 }}')}</code> 2</p>`);
});

// https://github.com/hexojs/hexo/issues/4317
Expand Down Expand Up @@ -1083,6 +1084,35 @@ describe('Post', () => {
data.content.trim().should.contains(highlightedHtml);
});

it('render() - escape & recover muilt {% raw %} and backticks', async () => {
const content = [
'`{{ 1 + 1 }}` {{ 1 + 2 }} `{{ 2 + 2 }}`',
'Text',
'{% raw %}',
'Raw 1',
'{% endraw %}',
'Another Text',
'{% raw %}',
'Raw 2',
'{% endraw %}'
].join('\n');

const data = await post.render(null, {
content,
engine: 'markdown'
});

data.content.trim().should.eql([
`<p><code>${escapeSwigTag('{{ 1 + 1 }}')}</code> 3 <code>${escapeSwigTag('{{ 2 + 2 }}')}</code><br>Text</p>`,
'',
'Raw 1',
'',
'<p>Another Text</p>',
'',
'Raw 2'
].join('\n'));
});

// https://github.com/hexojs/hexo/issues/4087
it('render() - issue #4087', async () => {
// Adopted from https://github.com/hexojs/hexo/issues/4087#issuecomment-596999486
Expand Down