Skip to content

Commit

Permalink
fix(tag/include_code): prevent path traversal (#5251)
Browse files Browse the repository at this point in the history
Co-authored-by: uiolee <[email protected]>
Co-authored-by: yoshinorin <[email protected]>
  • Loading branch information
3 people authored Apr 16, 2024
1 parent cefee92 commit b5b63ca
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 30 deletions.
51 changes: 25 additions & 26 deletions lib/plugins/tag/include_code.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { exists, readFile } from 'hexo-fs';
import { basename, extname, join, posix } from 'path';
import { basename, extname, join } from 'path';
import { url_for } from 'hexo-util';
import type Hexo from '../../hexo';

const rCaptionTitleFile = /(.*)?(?:\s+|^)(\/*\S+)/;
Expand Down Expand Up @@ -47,32 +47,31 @@ export = (ctx: Hexo) => function includeCodeTag(args: string[]) {
// If the language is not defined, use file extension instead
lang = lang || extname(path).substring(1);

const src = join(ctx.source_dir, codeDir, path);
const source = join(codeDir, path).replace(/\\/g, '/');

// If the title is not defined, use file name instead
const title = match[1] || basename(path);
const caption = `<span>${title}</span><a href="${posix.join(ctx.config.root, codeDir, path)}">view raw</a>`;

return exists(src).then(exist => {
if (exist) return readFile(src);
}).then(code => {
if (!code) return;
// Prevent path traversal: https://github.com/hexojs/hexo/issues/5250
const Page = ctx.model('Page');
const doc = Page.findOne({ source });
if (!doc) return;

const lines = code.split('\n');
code = lines.slice(from, to).join('\n').trim();
let code = doc.content;
const lines = code.split('\n');
code = lines.slice(from, to).join('\n').trim();

if (ctx.extend.highlight.query(ctx.config.syntax_highlighter)) {
const options = {
lang,
caption,
lines_length: lines.length
};
return ctx.extend.highlight.exec(ctx.config.syntax_highlighter, {
context: ctx,
args: [code, options]
});
}
// If the title is not defined, use file name instead
const title = match[1] || basename(path);
const caption = `<span>${title}</span><a href="${url_for.call(ctx, doc.path)}">view raw</a>`;

return `<pre><code>${code}</code></pre>`;
});
if (ctx.extend.highlight.query(ctx.config.syntax_highlighter)) {
const options = {
lang,
caption,
lines_length: lines.length
};
return ctx.extend.highlight.exec(ctx.config.syntax_highlighter, {
context: ctx,
args: [code, options]
});
}
return `<pre><code>${code}</code></pre>`;
};
12 changes: 8 additions & 4 deletions test/scripts/tags/include_code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ describe('include_code', () => {
const defaultCfg = JSON.parse(JSON.stringify(hexo.config));

const fixture = [
'if (tired && night){',
'if (tired && night) {',
' sleep();',
'}'
].join('\n');

const code = args => includeCode(args.split(' '));

before(() => writeFile(path, fixture));
before(async () => {
await writeFile(path, fixture);
await hexo.init();
await hexo.load();
});

beforeEach(() => {
hexo.config = JSON.parse(JSON.stringify(defaultCfg));
Expand Down Expand Up @@ -95,7 +99,7 @@ describe('include_code', () => {

it('to', async () => {
const fixture = [
'if (tired && night){',
'if (tired && night) {',
' sleep();'
].join('\n');
const expected = highlight(fixture, {
Expand Down Expand Up @@ -173,7 +177,7 @@ describe('include_code', () => {

it('to', async () => {
const fixture = [
'if (tired && night){',
'if (tired && night) {',
' sleep();'
].join('\n');
const expected = prismHighlight(fixture, {
Expand Down

0 comments on commit b5b63ca

Please sign in to comment.