Skip to content

Commit de619bb

Browse files
committed
fix(escapeAllSwigTags): Prevent swig tag prefix collision during escaping. (#5635)
1 parent 25dd2ac commit de619bb

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

lib/extend/tag.ts

+14
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

+3-3
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class PostRenderEscape {
8484
* @param {string} str
8585
* @returns string
8686
*/
87-
escapeAllSwigTags(str: string) {
87+
escapeAllSwigTags(str: string, block_swig_tag_map: { [name: string]: boolean }) {
8888
if (!/(\{\{.+?\}\})|(\{#.+?#\})|(\{%.+?%\})/s.test(str)) {
8989
return str;
9090
}
@@ -158,7 +158,7 @@ class PostRenderEscape {
158158
buffer = '';
159159
} else if (char === '%' && next_char === '}' && swig_string_quote === '') { // From swig back to plain text
160160
idx++;
161-
if (swig_tag_name !== '' && str.includes(`end${swig_tag_name}`)) {
161+
if (swig_tag_name !== '' && (block_swig_tag_map[swig_tag_name] ?? false)) {
162162
state = STATE_SWIG_FULL_TAG;
163163
swig_start_idx[state] = idx;
164164
} else {
@@ -518,7 +518,7 @@ class Post {
518518
data.content = cacheObj.escapeCodeBlocks(data.content);
519519
// Escape all Nunjucks/Swig tags
520520
if (disableNunjucks === false) {
521-
data.content = cacheObj.escapeAllSwigTags(data.content);
521+
data.content = cacheObj.escapeAllSwigTags(data.content, tag.block_swig_tag_map);
522522
}
523523

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

test/scripts/hexo/post.ts

+30
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,36 @@ describe('Post', () => {
15251525
data.content.should.contains('22222');
15261526
});
15271527

1528+
it('render() - tag prefix collision during escape swig tag (issue #5635)', async () => {
1529+
hexo.extend.tag.register('testtagblock', (args, content) => {
1530+
return 'rendered_test_tag_block';
1531+
}, { ends: true });
1532+
hexo.extend.tag.register('testtag', args => {
1533+
return 'rendered_test_tag';
1534+
});
1535+
1536+
const content = [
1537+
'x{% testtag name %}',
1538+
'## Title',
1539+
'{% testtagblock %}',
1540+
'content in block tag',
1541+
'{% endtesttagblock %}'
1542+
].join('\n');
1543+
1544+
const data = await post.render('', {
1545+
content,
1546+
engine: 'markdown'
1547+
});
1548+
1549+
hexo.extend.tag.unregister('testtagblock');
1550+
hexo.extend.tag.unregister('testtag');
1551+
1552+
data.content.should.contains('rendered_test_tag_block');
1553+
data.content.should.contains('rendered_test_tag');
1554+
data.content.should.contains('<h2');
1555+
data.content.should.not.contains('## Title');
1556+
});
1557+
15281558
it('render() - incomplete tags throw error', async () => {
15291559
const content = 'nunjucks should throw {# } error';
15301560

0 commit comments

Comments
 (0)