diff --git a/install/package.json b/install/package.json index a10b527155..3c9d48dc7c 100644 --- a/install/package.json +++ b/install/package.json @@ -106,10 +106,10 @@ "nodebb-plugin-spam-be-gone": "2.3.2", "nodebb-plugin-web-push": "0.7.5", "nodebb-rewards-essentials": "1.0.2", - "nodebb-theme-harmony": "2.1.18", + "nodebb-theme-harmony": "2.1.19", "nodebb-theme-lavender": "7.1.19", "nodebb-theme-peace": "2.2.48", - "nodebb-theme-persona": "14.1.12", + "nodebb-theme-persona": "14.1.13", "nodebb-widget-essentials": "7.0.40", "nodemailer": "7.0.6", "nprogress": "0.2.0", diff --git a/public/src/modules/topicList.js b/public/src/modules/topicList.js index 6396bb9e8e..bc5a6e4abd 100644 --- a/public/src/modules/topicList.js +++ b/public/src/modules/topicList.js @@ -53,7 +53,7 @@ define('topicList', [ handleBack.init(function (after, handleBackCallback) { loadTopicsCallback(after, 1, function (data, loadCallback) { - onTopicsLoaded(templateName, data.topics, ajaxify.data.showSelect, 1, function () { + onTopicsLoaded(templateName, data, ajaxify.data.showSelect, 1, function () { handleBackCallback(); loadCallback(); }); @@ -166,7 +166,7 @@ define('topicList', [ } loadTopicsCallback(after, direction, function (data, done) { - onTopicsLoaded(templateName, data.topics, ajaxify.data.showSelect, direction, done); + onTopicsLoaded(templateName, data, ajaxify.data.showSelect, direction, done); }); }; @@ -187,7 +187,8 @@ define('topicList', [ }); } - function onTopicsLoaded(templateName, topics, showSelect, direction, callback) { + function onTopicsLoaded(templateName, data, showSelect, direction, callback) { + let { topics } = data; if (!topics || !topics.length) { $('#load-more-btn').hide(); return callback(); @@ -212,6 +213,7 @@ define('topicList', [ const tplData = { topics: topics, showSelect: showSelect, + 'reputation:disabled': data['reputation:disabled'], template: { name: templateName, }, diff --git a/src/controllers/recent.js b/src/controllers/recent.js index 5699fee1b7..656958463b 100644 --- a/src/controllers/recent.js +++ b/src/controllers/recent.js @@ -79,6 +79,7 @@ recentController.getData = async function (req, url, sort) { data.selectedTag = tagData.selectedTag; data.selectedTags = tagData.selectedTags; data['feeds:disableRSS'] = meta.config['feeds:disableRSS'] || 0; + data['reputation:disabled'] = meta.config['reputation:disabled']; if (!meta.config['feeds:disableRSS']) { data.rssFeedUrl = `${relative_path}/${url}.rss`; if (req.loggedIn) { diff --git a/src/database/redis/connection.js b/src/database/redis/connection.js index 8792bbdf3f..7f0b1912f8 100644 --- a/src/database/redis/connection.js +++ b/src/database/redis/connection.js @@ -69,10 +69,6 @@ connection.connect = async function (options) { }).catch((err) => { winston.error('Error connecting to Redis:', err); }); - - if (options.password) { - cxn.auth({ password: options.password }); - } }); }; diff --git a/src/middleware/index.js b/src/middleware/index.js index 67d8e2faa0..14cb3138e1 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -145,12 +145,18 @@ middleware.logApiUsage = async function logApiUsage(req, res, next) { }; middleware.routeTouchIcon = function routeTouchIcon(req, res) { - if (meta.config['brand:touchIcon'] && validator.isURL(meta.config['brand:touchIcon'])) { - return res.redirect(meta.config['brand:touchIcon']); + const brandTouchIcon = meta.config['brand:touchIcon']; + if (brandTouchIcon && validator.isURL(brandTouchIcon)) { + return res.redirect(brandTouchIcon); } + let iconPath = ''; - if (meta.config['brand:touchIcon']) { - iconPath = path.join(nconf.get('upload_path'), meta.config['brand:touchIcon'].replace(/assets\/uploads/, '')); + if (brandTouchIcon) { + const uploadPath = nconf.get('upload_path'); + iconPath = path.join(uploadPath, brandTouchIcon.replace(/assets\/uploads/, '')); + if (!iconPath.startsWith(uploadPath)) { + return res.status(404).send('Not found'); + } } else { iconPath = path.join(nconf.get('base_dir'), 'public/images/touch/512.png'); } diff --git a/src/webserver.js b/src/webserver.js index ab8dc5bc0d..18f57faa40 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -227,6 +227,9 @@ function setupHelmet(app) { function setupFavicon(app) { let faviconPath = meta.config['brand:favicon'] || 'favicon.ico'; faviconPath = path.join(nconf.get('base_dir'), 'public', faviconPath.replace(/assets\/uploads/, 'uploads')); + if (!faviconPath.startsWith(nconf.get('upload_path'))) { + faviconPath = path.join(nconf.get('base_dir'), 'public', 'favicon.ico'); + } if (file.existsSync(faviconPath)) { app.use(nconf.get('relative_path'), favicon(faviconPath)); } diff --git a/test/controllers.js b/test/controllers.js index b2174d8cf9..d79cf6de04 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -6,8 +6,8 @@ const fs = require('fs'); const path = require('path'); const util = require('util'); -const request = require('../src/request'); const db = require('./mocks/databasemock'); +const request = require('../src/request'); const api = require('../src/api'); const categories = require('../src/categories'); const topics = require('../src/topics'); @@ -692,6 +692,16 @@ describe('Controllers', () => { assert(body); }); + it('should 404 if brand:touchIcon is not valid', async () => { + const oldValue = meta.config['brand:touchIcon']; + meta.config['brand:touchIcon'] = '../../not/valid'; + + const { response, body } = await request.get(`${nconf.get('url')}/apple-touch-icon`); + assert.strictEqual(response.statusCode, 404); + assert.strictEqual(body, 'Not found'); + meta.config['brand:touchIcon'] = oldValue; + }); + it('should error if guests do not have search privilege', async () => { const { response, body } = await request.get(`${nconf.get('url')}/api/users?query=bar§ion=sort-posts`);