From 30ba8e82476e992dcaf228c41083a68f89d28314 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 29 Sep 2025 14:04:07 +0000 Subject: [PATCH 1/6] chore: incrementing version number - v4.5.2 --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index f9e5b8b0ed..ea5908ca1d 100644 --- a/install/package.json +++ b/install/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "4.5.1", + "version": "4.5.2", "homepage": "https://www.nodebb.org", "repository": { "type": "git", @@ -201,4 +201,4 @@ "url": "https://github.com/barisusakli" } ] -} +} \ No newline at end of file From 9a596d67f34153cbd0cdaf8443fbcce7cbdee7d3 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 29 Sep 2025 14:04:08 +0000 Subject: [PATCH 2/6] chore: update changelog for v4.5.2 --- CHANGELOG.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index beaab4c40c..c35feb4d24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,75 @@ +#### v4.5.2 (2025-09-29) + +##### Chores + +* remove obsolete deprecation (52fec493) +* up persona (405d2172) +* incrementing version number - v4.5.1 (69f4b61f) +* update changelog for v4.5.1 (a9fffd7c) +* incrementing version number - v4.5.0 (f05c5d06) +* incrementing version number - v4.4.6 (074043ad) +* incrementing version number - v4.4.5 (6f106923) +* incrementing version number - v4.4.4 (d323af44) +* incrementing version number - v4.4.3 (d354c2eb) +* incrementing version number - v4.4.2 (55c510ae) +* incrementing version number - v4.4.1 (5ae79b4e) +* incrementing version number - v4.4.0 (0a75eee3) +* incrementing version number - v4.3.2 (b92b5d80) +* incrementing version number - v4.3.1 (308e6b9f) +* incrementing version number - v4.3.0 (bff291db) +* incrementing version number - v4.2.2 (17fecc24) +* incrementing version number - v4.2.1 (852a270c) +* incrementing version number - v4.2.0 (87581958) +* incrementing version number - v4.1.1 (b2afbb16) +* incrementing version number - v4.1.0 (36c80850) +* incrementing version number - v4.0.6 (4a52fb2e) +* incrementing version number - v4.0.5 (1792a62b) +* incrementing version number - v4.0.4 (b1125cce) +* incrementing version number - v4.0.3 (2b65c735) +* incrementing version number - v4.0.2 (73fe5fcf) +* incrementing version number - v4.0.1 (a461b758) +* incrementing version number - v4.0.0 (c1eaee45) + +##### New Features + +* add a term param to recent controller so it can be controller without req.query.term (9c18c6fe) +* add a new hook to override generateUrl in navigator.js (68a8db85) +* add topic templates per category, closes #13649 (0311b98e) + +##### Bug Fixes + +* skip header checking during note assertion if test runner is active (7abdfd86) +* update note assertion topic members check to simpler posts.exists check (d0c05826) +* re-jig handling of ap tag values so that only hashtags are considered (not Piefed community tags, etc.) (4d68e3fe) +* missing actor assertion on 1b12 announced upboat (f9edb13f) +* use parameterized query for key lookup (6cca55e3) +* add pre-processing step to title generation logic so sbd doesn't fall over so badly (f7c47429) +* switch to action (f7bbec7c) +* handle cases where incoming ap object tag can be a non-array (b66c30a2) +* local pids not always converted to absolute URLs on topic actor controller (f67942ca) +* #13657, fix remote category data inconsistency in `sendNotificationToPostOwner` (225bf85e) +* don't show votes on unread if rep system disabled (dfe19a98) +* if reputation is disabled hide votes on /recent (8a786c71) +* favicon path (e2dc592c) +* check brand:touchIcon for correct path (56fad0be) +* remove .auth call (f9ddbeba) +* port the try/catch for notes.assert from develop (f9688b36) +* perform Link header check on note assertion only when skipChecks is falsy (953c051c) +* make auto-categorization logic case-insensitive (527f27af) +* closes #13641, log test email sending errors server side (b3ffa007) +* pass object to.auth (290a9395) +* **deps:** bump 2factor to 7.6.0 (d1f5060f) + +##### Other Changes + +* remove unused (a6674f67) +* fix (a37521b0) + +##### Performance Improvements + +* update upgrade script to use bulk methods (0a2fa45d) +* update old upgrade scripts to use bulkSet/Add (32d0ee48) + #### v4.5.1 (2025-09-04) ##### Chores From c3df68f2ed34cca590946a19182bd29c924f5075 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 30 Sep 2025 11:05:42 -0400 Subject: [PATCH 3/6] fix: don\'t begin processing local login if the passed-in username isn't even valid --- src/controllers/authentication.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index fef6f088b6..d5a0965d7b 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -420,6 +420,10 @@ authenticationController.localLogin = async function (req, username, password, n } const userslug = slugify(username); + if (!utils.isUserNameValid(username) || !userslug) { + return next(new Error('[[error:invalid-username]]')); + } + const uid = await user.getUidByUserslug(userslug); try { const [userData, isAdminOrGlobalMod, canLoginIfBanned] = await Promise.all([ From 4776d012812f1b250fe24687c51128dc5c752ad8 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 Oct 2025 11:00:03 -0400 Subject: [PATCH 4/6] sec: disallow checkHeader from returning a URL from a different origin than the passed-in URL --- src/activitypub/index.js | 80 ++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/src/activitypub/index.js b/src/activitypub/index.js index 11f16322e2..1c0f4ce13d 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -565,42 +565,58 @@ ActivityPub.buildRecipients = async function (object, { pid, uid, cid }) { ActivityPub.checkHeader = async (url, timeout) => { timeout = timeout || meta.config.activitypubProbeTimeout || 2000; - const { response } = await request.head(url, { - timeout, - }); - const { headers } = response; - if (headers && headers.link) { - // Multiple link headers could be combined - const links = headers.link.split(','); - let apLink = false; - links.forEach((link) => { - let parts = link.split(';'); - const url = parts.shift().match(/<(.+)>/)[1]; - if (!url || apLink) { - return; - } - - parts = parts - .map(p => p.trim()) - .reduce((memo, cur) => { - cur = cur.split('='); - if (cur.length < 2) { - cur.push(''); - } - memo[cur[0]] = cur[1].slice(1, -1); - return memo; - }, {}); - - if (parts.rel === 'alternate' && parts.type === 'application/activity+json') { - apLink = url; - } + try { + const { hostname } = new URL(url); + const { response } = await request.head(url, { + timeout, }); + const { headers } = response; - return apLink; + // headers.link = + if (headers && headers.link) { + // Multiple link headers could be combined + const links = headers.link.split(','); + let apLink = false; + + links.forEach((link) => { + let parts = link.split(';'); + const url = parts.shift().match(/<(.+)>/)[1]; + if (!url || apLink) { + return; + } + + parts = parts + .map(p => p.trim()) + .reduce((memo, cur) => { + cur = cur.split('='); + if (cur.length < 2) { + cur.push(''); + } + memo[cur[0]] = cur[1].slice(1, -1); + return memo; + }, {}); + + if (parts.rel === 'alternate' && parts.type === 'application/activity+json') { + apLink = url; + } + }); + + if (apLink) { + const { hostname: compare } = new URL(apLink); + if (hostname !== compare) { + apLink = false; + } + } + + return apLink; + } + + return false; + } catch (e) { + ActivityPub.helpers.log(`[activitypub/checkHeader] Failed on ${url}: ${e.message}`); + return false; } - - return false; }; ActivityPub.probe = async ({ uid, url }) => { From 9cee799937c369acb300c37e702a7779f8e80f9f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 Oct 2025 11:53:57 -0400 Subject: [PATCH 5/6] fix: force outgoing page on direct access to `/ap` handler --- src/controllers/activitypub/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/controllers/activitypub/index.js b/src/controllers/activitypub/index.js index 121c8536aa..c64ef9ef57 100644 --- a/src/controllers/activitypub/index.js +++ b/src/controllers/activitypub/index.js @@ -48,6 +48,11 @@ Controller.fetch = async (req, res, next) => { } } + // Force outgoing links page on direct access + if (!res.locals.isAPI) { + url = new URL(`outgoing?url=${encodeURIComponent(url.href)}`, nconf.get('url')); + } + helpers.redirect(res, url.href, false); } catch (e) { if (!url || !url.href) { From 56a9336611cc19788686c63b5d2768e37859fd9e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 Oct 2025 12:52:09 -0400 Subject: [PATCH 6/6] docs: update openapi schema to refer to try.nodebb.org instead of example.org --- public/openapi/read/ap.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/openapi/read/ap.yaml b/public/openapi/read/ap.yaml index 0704cc6dab..89bee103c5 100644 --- a/public/openapi/read/ap.yaml +++ b/public/openapi/read/ap.yaml @@ -14,8 +14,8 @@ get: name: resource schema: type: string - description: A URL to query for potential ActivityPub resource - example: 'https://example.org/ap' + description: A URL-encoded address to query for potential ActivityPub resource + example: 'https://try.nodebb.org/uid/1' responses: "200": description: Sent if the `/api` prefix is used. The `X-Redirect` header is sent with the redirection target. @@ -24,7 +24,7 @@ get: schema: type: string "307": - description: Redirect the user to the local representation or original URL. + description: Redirect the user to the local representation or /outgoing interstitial page for original URL. headers: Location: schema: