| @@ -8,7 +8,8 @@ import sanitize from 'sanitize-filename'; | ||
| 8 | 8 | import fetch from 'node-fetch'; |
| 9 | 9 | |
| 10 | 10 | import { UNSAFE_EXTENSIONS } from '../constants.js'; |
| 11 | 11 | import { clientRelativePath, isValidUrl } from '../util.js'; |
| 12 | +import { getHostFromUrl, isHostWhitelisted } from './content-manager.js'; | |
| 12 | 13 | |
| 13 | 14 | const VALID_CATEGORIES = ['bgm', 'ambient', 'blip', 'live2d', 'vrm', 'character', 'temp']; |
| 14 | 15 | |
| @@ -189,9 +190,21 @@ router.post('/get', async (request, response) => { | ||
| 189 | 190 | * @returns {void} |
| 190 | 191 | */ |
| 191 | 192 | router.post('/download', async (request, response) => { |
| 192 | - const url = request.body.url; | |
| 193 | + try { | |
| 194 | + if (!isValidUrl(request.body.url)) { | |
| 195 | + console.warn('Asset download failed: Must be a valid URL'); | |
| 196 | + return response.sendStatus(400); | |
| 197 | + } | |
| 198 | + | |
| 199 | + const url = String(request.body.url); | |
| 193 | 200 | const inputCategory = request.body.category; |
| 194 | 201 | |
| 202 | + const host = getHostFromUrl(url); | |
| 203 | + if (!isHostWhitelisted(host)) { | |
| 204 | + console.error(`Received an import for "${host}", but site is not whitelisted. This domain must be added to the config key "whitelistImportDomains" to allow import from this source.`); | |
| 205 | + return response.sendStatus(404); | |
| 206 | + } | |
| 207 | + | |
| 195 | 208 | // Check category |
| 196 | 209 | let category = null; |
| 197 | 210 | for (let i of VALID_CATEGORIES) |
| @@ -213,7 +226,6 @@ router.post('/download', async (request, response) => { | ||
| 213 | 226 | const file_path = path.join(request.user.directories.assets, category, request.body.filename); |
| 214 | 227 | console.info('Request received to download', url, 'to', file_path); |
| 215 | 228 | |
| 216 | - try { | |
| 217 | 229 | // Download to temp |
| 218 | 230 | const res = await fetch(url); |
| 219 | 231 | if (!res.ok || res.body === null) { |
| @@ -872,7 +872,7 @@ function getUuidFromUrl(url) { | ||
| 872 | 872 | * @param {String} url URL to strip |
| 873 | 873 | * @returns {String} Domain name |
| 874 | 874 | */ |
| 875 | 875 | export function getHostFromUrl(url) { |
| 876 | 876 | try { |
| 877 | 877 | const urlObj = new URL(url); |
| 878 | 878 | return urlObj.hostname; |
| @@ -886,7 +886,7 @@ function getHostFromUrl(url) { | ||
| 886 | 886 | * @param {String} host Host to check |
| 887 | 887 | * @returns {boolean} If the host is on the whitelist. |
| 888 | 888 | */ |
| 889 | 889 | export function isHostWhitelisted(host) { |
| 890 | 890 | return WHITELIST_GENERIC_URL_DOWNLOAD_SOURCES.includes(host); |
| 891 | 891 | } |
| 892 | 892 | |