diff --git a/install/package.json b/install/package.json index f8b6380ade..fc78146d4a 100644 --- a/install/package.json +++ b/install/package.json @@ -97,7 +97,7 @@ "multer": "2.0.2", "nconf": "0.13.0", "nodebb-plugin-2factor": "7.6.1", - "nodebb-plugin-composer-default": "10.3.10", + "nodebb-plugin-composer-default": "10.3.11", "nodebb-plugin-dbsearch": "6.3.5", "nodebb-plugin-emoji": "6.0.5", "nodebb-plugin-emoji-android": "4.1.1", diff --git a/loader.js b/loader.js index 427c952ff4..334e156192 100644 --- a/loader.js +++ b/loader.js @@ -2,7 +2,6 @@ const nconf = require('nconf'); const fs = require('fs'); -const url = require('url'); const path = require('path'); const { fork } = require('child_process'); const logrotate = require('logrotate-stream'); @@ -140,7 +139,7 @@ function getPorts() { console.log('[cluster] url is undefined, please check your config.json'); process.exit(); } - const urlObject = url.parse(_url); + const urlObject = new URL(_url); let port = nconf.get('PORT') || nconf.get('port') || urlObject.port || 4567; if (!Array.isArray(port)) { port = [port]; diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 6f3d4dcd69..324e11c9d7 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -198,10 +198,15 @@ ajaxify.widgets = { render: render }; ajaxify.currentPage = url.split(/[?#]/)[0]; ajaxify.requestedPage = null; if (window.history && window.history.pushState) { + const prependSlash = url && !url.startsWith('?') && !url.startsWith('#'); const { relative_path } = config; + const historyUrl = prependSlash ? + (relative_path + '/' + url) : + relative_path + (url || (relative_path ? '' : '/')); + window.history[!quiet ? 'pushState' : 'replaceState']({ url: url, - }, '', relative_path + (url ? '/' + url : (relative_path ? '' : '/'))); + }, '', historyUrl); } }; @@ -402,8 +407,11 @@ ajaxify.widgets = { render: render }; }; ajaxify.removeRelativePath = function (url) { - if (url.startsWith(config.relative_path.slice(1))) { - url = url.slice(config.relative_path.length); + if (config.relative_path && url.startsWith(config.relative_path.slice(1))) { + url = url.slice(config.relative_path.length - 1); + if (url.startsWith('/')) { + url = url.slice(1); + } } return url; }; @@ -565,10 +573,16 @@ $(document).ready(function () { if (ev !== null && ev.state) { const { returnPath } = ev.state; if (ev.state.url === null && returnPath !== undefined) { + const url = returnPath; + const prependSlash = url && !url.startsWith('?') && !url.startsWith('#'); const { relative_path } = config; + const historyUrl = prependSlash ? + (relative_path + '/' + url) : + relative_path + (url || (relative_path ? '' : '/')); + window.history.replaceState({ url: returnPath, - }, '', relative_path + (returnPath ? '/' + returnPath : (relative_path ? '' : '/'))); + }, '', historyUrl); } else if (ev.state.url !== undefined) { ajaxify.handleTransientElements(); ajaxify.go(ev.state.url, function () { diff --git a/src/api/helpers.js b/src/api/helpers.js index 298725e915..642774856d 100644 --- a/src/api/helpers.js +++ b/src/api/helpers.js @@ -1,6 +1,5 @@ 'use strict'; -const url = require('url'); const user = require('../user'); const topics = require('../topics'); const posts = require('../posts'); @@ -29,7 +28,7 @@ exports.buildReqObject = (req, payload) => { const referer = headers.referer || ''; if (!host) { - host = url.parse(referer).host || ''; + host = new URL(referer).host || ''; } return { diff --git a/src/controllers/home.js b/src/controllers/home.js index ea596f972f..e01c780e38 100644 --- a/src/controllers/home.js +++ b/src/controllers/home.js @@ -1,7 +1,5 @@ 'use strict'; -const url = require('url'); - const plugins = require('../plugins'); const meta = require('../meta'); const user = require('../user'); @@ -32,19 +30,19 @@ async function rewrite(req, res, next) { let parsedUrl; try { - parsedUrl = url.parse(route, true); + parsedUrl = new URL(route, 'http://localhost.com'); } catch (err) { return next(err); } - const { pathname } = parsedUrl; + const pathname = parsedUrl.pathname.replace(/^\/+/, ''); const hook = `action:homepage.get:${pathname}`; if (!plugins.hooks.hasListeners(hook)) { req.url = req.path + (!req.path.endsWith('/') ? '/' : '') + pathname; } else { res.locals.homePageRoute = pathname; } - req.query = Object.assign(parsedUrl.query, req.query); + req.query = Object.assign(Object.fromEntries(parsedUrl.searchParams), req.query); next(); } diff --git a/src/install.js b/src/install.js index 856732f631..c69754c700 100644 --- a/src/install.js +++ b/src/install.js @@ -217,19 +217,17 @@ async function completeConfigSetup(config) { } // If port is explicitly passed via install vars, use it. Otherwise, glean from url if set. - const urlObj = url.parse(config.url); + const urlObj = new URL(config.url); if (urlObj.port && (!install.values || !install.values.hasOwnProperty('port'))) { config.port = urlObj.port; } - // Remove trailing slash from non-subfolder installs - if (urlObj.path === '/') { - urlObj.path = ''; - urlObj.pathname = ''; + config.url = urlObj.toString(); + // Remove trailing slash from URL + if (config.url.endsWith('/')) { + config.url = config.url.slice(0, -1); } - config.url = url.format(urlObj); - // ref: https://github.com/indexzero/nconf/issues/300 delete config.type; diff --git a/src/prestart.js b/src/prestart.js index 57b5f0590e..a85b14d6a8 100644 --- a/src/prestart.js +++ b/src/prestart.js @@ -1,7 +1,6 @@ 'use strict'; const nconf = require('nconf'); -const url = require('url'); const winston = require('winston'); const path = require('path'); const chalk = require('chalk'); @@ -89,12 +88,13 @@ function loadConfig(configFile) { if (!nconf.get('sessionKey')) { nconf.set('sessionKey', 'express.sid'); } + const url = nconf.get('url'); + if (url) { + const urlObject = new URL(url); - if (nconf.get('url')) { - nconf.set('url', nconf.get('url').replace(/\/$/, '')); - nconf.set('url_parsed', url.parse(nconf.get('url'))); + nconf.set('url', url.replace(/\/$/, '')); + nconf.set('url_parsed', urlObject); // Parse out the relative_url and other goodies from the configured URL - const urlObject = url.parse(nconf.get('url')); const relativePath = urlObject.pathname !== '/' ? urlObject.pathname.replace(/\/+$/, '') : ''; nconf.set('base_url', `${urlObject.protocol}//${urlObject.host}`); nconf.set('secure', urlObject.protocol === 'https:'); diff --git a/test/authentication.js b/test/authentication.js index 7fa44b964b..0e3cfc79ca 100644 --- a/test/authentication.js +++ b/test/authentication.js @@ -140,7 +140,7 @@ describe('authentication', () => { it('should regenerate the session identifier on successful login', async () => { const matchRegexp = /express\.sid=s%3A(.+?);/; - const { hostname, path } = url.parse(nconf.get('url')); + const { hostname, path } = new URL(nconf.get('url')); const sid = String(jar.store.idx[hostname][path]['express.sid']).match(matchRegexp)[1]; await helpers.logoutUser(jar); const newJar = (await helpers.loginUser('regular', 'regularpwd')).jar; diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index 2658cda500..e2a15cdbb5 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -46,7 +46,7 @@ nconf.defaults({ relative_path: '', }); -const urlObject = url.parse(nconf.get('url')); +const urlObject = new URL(nconf.get('url')); const relativePath = urlObject.pathname !== '/' ? urlObject.pathname : ''; nconf.set('relative_path', relativePath); nconf.set('asset_base_url', `${relativePath}/assets`); @@ -134,9 +134,6 @@ module.exports = db; before(async function () { this.timeout(30000); - // Parse out the relative_url and other goodies from the configured URL - const urlObject = url.parse(nconf.get('url')); - nconf.set('core_templates_path', path.join(__dirname, '../../src/views')); nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates')); nconf.set('theme_config', path.join(nconf.get('themes_path'), 'nodebb-theme-persona', 'theme.json')); diff --git a/webpack.common.js b/webpack.common.js index 7ea12755ae..44c7741cae 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -1,7 +1,6 @@ 'use strict'; const path = require('path'); -const url = require('url'); const nconf = require('nconf'); const activePlugins = require('./build/active_plugins.json'); @@ -12,7 +11,7 @@ if (relativePath === undefined) { file: path.resolve(__dirname, nconf.any(['config', 'CONFIG']) || 'config.json'), }); - const urlObject = url.parse(nconf.get('url')); + const urlObject = new URL(nconf.get('url')); relativePath = urlObject.pathname !== '/' ? urlObject.pathname.replace(/\/+$/, '') : ''; }