diff --git a/install/package.json b/install/package.json index 1126e4fbc7..5d454bf7ed 100644 --- a/install/package.json +++ b/install/package.json @@ -145,6 +145,7 @@ "tinycon": "0.6.8", "toobusy-js": "0.5.1", "tough-cookie": "5.1.2", + "undici": "^7.10.0", "validator": "13.15.15", "webpack": "5.99.9", "webpack-merge": "6.0.1", diff --git a/src/request.js b/src/request.js index 86ad8c5fc7..3709aba2f6 100644 --- a/src/request.js +++ b/src/request.js @@ -8,10 +8,13 @@ const { CookieJar } = require('tough-cookie'); const fetchCookie = require('fetch-cookie').default; const { version } = require('../package.json'); +const plugins = require('./plugins'); const ttl = require('./cache/ttl'); const checkCache = ttl({ ttl: 1000 * 60 * 60, // 1 hour }); +let allowList = new Set(); +let initialized = false; exports.jar = function () { return new CookieJar(); @@ -19,6 +22,19 @@ exports.jar = function () { const userAgent = `NodeBB/${version.split('.').shift()}.x (${nconf.get('url')})`; +async function init() { + if (initialized) { + return; + } + + allowList.add(nconf.get('url_parsed').host); + const { allowed } = await plugins.hooks.fire('filter:request.init', { allowed: allowList }); + if (allowed instanceof Set) { + allowList = allowed; + } + initialized = true; +} + // Initialize fetch - somewhat hacky, but it's required for globalDispatcher to be available async function call(url, method, { body, timeout, jar, ...config } = {}) { const ok = await check(url); @@ -90,13 +106,15 @@ async function call(url, method, { body, timeout, jar, ...config } = {}) { // Checks url to ensure it is not in reserved IP range (private, etc.) async function check(url) { + await init(); + const { host } = new URL(url); - if (host === nconf.get('url_parsed').host) { + if (allowList.has(host)) { return true; } const cached = checkCache.get(url); - if (cached) { + if (cached !== undefined) { return cached; }