From 48924d3696812866d7e130af76841360ee4a7316 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:47:07 +0300 Subject: [PATCH] Improve asset downloader --- server.js | 15 +++++++- src/content-manager.js | 80 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 58d5944df..3eb86fe27 100644 --- a/server.js +++ b/server.js @@ -5070,7 +5070,7 @@ app.post('/asset_download', jsonParser, async (request, response) => { const url = request.body.url; const inputCategory = request.body.category; const inputFilename = sanitize(request.body.filename); - const validCategories = ["bgm", "ambient"] + const validCategories = ["bgm", "ambient"]; // Check category let category = null @@ -5094,6 +5094,16 @@ app.post('/asset_download', jsonParser, async (request, response) => { return response.sendStatus(400); } + if (contentManager.unsafeExtensions.some(ext => inputFilename.toLowerCase().endsWith(ext))) { + console.debug("Bad request: forbidden file extension."); + return response.sendStatus(400); + } + + if (inputFilename.startsWith('.')) { + console.debug("Bad request: filename cannot start with '.'"); + return response.sendStatus(400); + } + const safe_input = path.normalize(inputFilename).replace(/^(\.\.(\/|\\|$))+/, ''); const temp_path = path.join(directories.assets, "temp", safe_input) const file_path = path.join(directories.assets, category, safe_input) @@ -5103,6 +5113,9 @@ app.post('/asset_download', jsonParser, async (request, response) => { // Download to temp const downloadFile = (async (url, temp_path) => { const res = await fetch(url); + if (!res.ok) { + throw new Error(`Unexpected response ${res.statusText}`); + } const destination = path.resolve(temp_path); // Delete if previous download failed if (fs.existsSync(temp_path)) { diff --git a/src/content-manager.js b/src/content-manager.js index e48eab877..e453d5f4a 100644 --- a/src/content-manager.js +++ b/src/content-manager.js @@ -1,10 +1,87 @@ const fs = require('fs'); -const path= require('path'); +const path = require('path'); const config = require(path.join(process.cwd(), './config.conf')); const contentDirectory = path.join(process.cwd(), 'default/content'); const contentLogPath = path.join(contentDirectory, 'content.log'); const contentIndexPath = path.join(contentDirectory, 'index.json'); +const unsafeExtensions = [ + ".php", + ".exe", + ".com", + ".dll", + ".pif", + ".application", + ".gadget", + ".msi", + ".jar", + ".cmd", + ".bat", + ".reg", + ".sh", + ".py", + ".js", + ".jse", + ".jsp", + ".pdf", + ".html", + ".htm", + ".hta", + ".vb", + ".vbs", + ".vbe", + ".cpl", + ".msc", + ".scr", + ".sql", + ".iso", + ".img", + ".dmg", + ".ps1", + ".ps1xml", + ".ps2", + ".ps2xml", + ".psc1", + ".psc2", + ".msh", + ".msh1", + ".msh2", + ".mshxml", + ".msh1xml", + ".msh2xml", + ".scf", + ".lnk", + ".inf", + ".reg", + ".doc", + ".docm", + ".docx", + ".dot", + ".dotm", + ".dotx", + ".xls", + ".xlsm", + ".xlsx", + ".xlt", + ".xltm", + ".xltx", + ".xlam", + ".ppt", + ".pptm", + ".pptx", + ".pot", + ".potm", + ".potx", + ".ppam", + ".ppsx", + ".ppsm", + ".pps", + ".ppam", + ".sldx", + ".sldm", + ".ws", +]; + function checkForNewContent() { try { if (config.skipContentCheck) { @@ -85,4 +162,5 @@ function getContentLog() { module.exports = { checkForNewContent, + unsafeExtensions, }