Skip to content

Commit 9d0b5e9

Browse files
committed
fix(escapeAllSwigTags): Prevent swig tag prefix collision during escaping. (hexojs#5635)
1 parent fbb69c3 commit 9d0b5e9

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

lib/extend/tag.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,23 @@ type RegisterOptions = {
206206
class Tag {
207207
public env: Environment;
208208
public source: string;
209+
public block_swig_tag_map: { [name: string]: boolean };
209210

210211
constructor() {
211212
this.env = new Environment(null, {
212213
autoescape: false
213214
});
215+
this.block_swig_tag_map = {
216+
if: true,
217+
for: true,
218+
each: true,
219+
all: true,
220+
macro: true,
221+
block: true,
222+
raw: true,
223+
filter: true,
224+
call: true
225+
};
214226
}
215227

216228
register(name: string, fn: TagFunction): void
@@ -246,6 +258,7 @@ class Tag {
246258
}
247259

248260
this.env.addExtension(name, tag);
261+
this.block_swig_tag_map[name] = !!options.ends;
249262
}
250263

251264
unregister(name: string): void {
@@ -254,6 +267,7 @@ class Tag {
254267
const { env } = this;
255268

256269
if (env.hasExtension(name)) env.removeExtension(name);
270+
delete this.block_swig_tag_map[name];
257271
}
258272

259273
render(str: string): Promise<any>;

lib/hexo/post.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class PostRenderEscape {
6868
* @param {string} str
6969
* @returns string
7070
*/
71-
escapeAllSwigTags(str: string) {
71+
escapeAllSwigTags(str: string, block_swig_tag_map: { [name: string]: boolean }) {
7272
if (!/(\{\{.+?\}\})|(\{#.+?#\})|(\{%.+?%\})/s.test(str)) {
7373
return str;
7474
}
@@ -142,7 +142,7 @@ class PostRenderEscape {
142142
buffer = '';
143143
} else if (char === '%' && next_char === '}' && swig_string_quote === '') { // From swig back to plain text
144144
idx++;
145-
if (swig_tag_name !== '' && str.includes(`end${swig_tag_name}`)) {
145+
if (swig_tag_name !== '' && (block_swig_tag_map[swig_tag_name] ?? false)) {
146146
state = STATE_SWIG_FULL_TAG;
147147
swig_start_idx[state] = idx;
148148
} else {
@@ -502,7 +502,7 @@ class Post {
502502
data.content = cacheObj.escapeCodeBlocks(data.content);
503503
// Escape all Nunjucks/Swig tags
504504
if (disableNunjucks === false) {
505-
data.content = cacheObj.escapeAllSwigTags(data.content);
505+
data.content = cacheObj.escapeAllSwigTags(data.content, tag.block_swig_tag_map);
506506
}
507507

508508
const options: { highlight?: boolean; } = data.markdown || {};

test/scripts/hexo/post.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,36 @@ describe('Post', () => {
15151515
data.content.should.contains('22222');
15161516
});
15171517

1518+
it('render() - tag prefix collision during escape swig tag (issue #5635)', async () => {
1519+
hexo.extend.tag.register('testtagblock', (args, content) => {
1520+
return 'rendered_test_tag_block';
1521+
}, { ends: true });
1522+
hexo.extend.tag.register('testtag', args => {
1523+
return 'rendered_test_tag';
1524+
});
1525+
1526+
const content = [
1527+
'x{% testtag name %}',
1528+
'## Title',
1529+
'{% testtagblock %}',
1530+
'content in block tag',
1531+
'{% endtesttagblock %}'
1532+
].join('\n');
1533+
1534+
const data = await post.render('', {
1535+
content,
1536+
engine: 'markdown'
1537+
});
1538+
1539+
hexo.extend.tag.unregister('testtagblock');
1540+
hexo.extend.tag.unregister('testtag');
1541+
1542+
data.content.should.contains('rendered_test_tag_block');
1543+
data.content.should.contains('rendered_test_tag');
1544+
data.content.should.contains('<h2');
1545+
data.content.should.not.contains('## Title');
1546+
});
1547+
15181548
it('render() - incomplete tags throw error', async () => {
15191549
const content = 'nunjucks should throw {# } error';
15201550

0 commit comments

Comments
 (0)