From 841556ea58c649f08a34162fef8acb36e950422f Mon Sep 17 00:00:00 2001 From: xwashere Date: Fri, 1 Dec 2023 08:20:01 -0500 Subject: [PATCH] restrict include to admin defined templates --- backend/UserConfig.ts | 4 +++- backend/templates/error.ts | 11 ++++++++--- backend/templates/parser.ts | 20 ++++++++++++++------ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/backend/UserConfig.ts b/backend/UserConfig.ts index ed74a70..510c47e 100644 --- a/backend/UserConfig.ts +++ b/backend/UserConfig.ts @@ -139,7 +139,9 @@ export class UserConfig { for (let part of ['title', 'description', 'sitename'] as ('title' | 'description' | 'sitename')[]) { if (config.embed[part] != null) { if (typeof config.embed[part] == 'string') { - config.embed[part] = prepareTemplate(config.embed[part] as string); + config.embed[part] = prepareTemplate(config.embed[part] as string, { + allowIncludeFile: true + }); } else throw new Error(`Template string for embed ${part} is not a string`); } else config.embed[part] = DEFAULT_EMBED[part]; } diff --git a/backend/templates/error.ts b/backend/templates/error.ts index 8297780..4485503 100644 --- a/backend/templates/error.ts +++ b/backend/templates/error.ts @@ -9,6 +9,9 @@ export class TemplateError extends Error { this.range = range; } + /** + * Formats the error. + */ public format(): string { let format = ''; @@ -39,13 +42,15 @@ export class TemplateError extends Error { } } - pend = Math.max(this.range.file.code.indexOf('\n', pend), pend); + if ((pend = this.range.file.code.indexOf('\n', pend)) == -1) { + pend = this.range.file.code.length - 1; + } if (fline == tline) { - format += `${fline.toString().padStart(5, ' ')} | ${this.range.file.code.substring(pstart, pend)}\n`; + format += `${fline.toString().padStart(5, ' ')} | ${this.range.file.code.substring(pstart, pend + 1)}\n`; format += `${fline.toString().padStart(5, ' ')} | ${' '.repeat(fcol)}^${'~'.repeat(Math.max(tcol - fcol, 0))}\n`; } else { - let lines = this.range.file.code.substring(pstart, pend).split('\n'); + let lines = this.range.file.code.substring(pstart, pend + 1).split('\n'); format += ` | /${'~'.repeat(lines[0].length)}v\n`; diff --git a/backend/templates/parser.ts b/backend/templates/parser.ts index 70d7400..f0ef0f0 100644 --- a/backend/templates/parser.ts +++ b/backend/templates/parser.ts @@ -130,7 +130,15 @@ function getTemplateTokens(src: string): TemplateToken[] { return tokens; } -export function prepareTemplate(src: string): TemplateOp { +export type PrepareTemplateOptions = { + allowIncludeFile?: boolean; +}; + +export function prepareTemplate(src: string, config?: PrepareTemplateOptions): TemplateOp { + let options = { + includeFiles: config?.allowIncludeFile ?? false + }; + type ParserStackEntry = { pos: number }; @@ -263,16 +271,16 @@ export function prepareTemplate(src: string): TemplateOp { // include is executed early if (name.toLowerCase() == 'include') { if (nargs['file'] != null) { - // TODO: this NEEDS to be restricted before ass 0.15.0 is released - // its extremely insecure and should be restricted to things - // set by operators, users can have their own template inclusion - // thing that doesnt depend on reading files + // security check! + if (!options.includeFiles) { + throw new TemplateSyntaxError('You are not allowed to include files', { file: file, from: tokens[start].from, to: tokens[pos - 1].to }); + } if (typeof nargs['file'] == 'string') { if (fs.existsSync(nargs['file'])) { let template = fs.readFileSync(nargs['file'], { encoding: 'utf-8' }); - let tl = prepareTemplate(template); + let tl = prepareTemplate(template, config); return tl; } else throw new TemplateSyntaxError('File does not exist', { file: file, from: tokens[start].from, to: tokens[pos - 1].to});