mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 01:26:12 +02:00
Merge branch 'master' into develop
This commit is contained in:
72
CHANGELOG.md
72
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
|
||||
|
||||
@@ -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",
|
||||
@@ -202,4 +202,4 @@
|
||||
"url": "https://github.com/barisusakli"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -591,42 +591,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 }) => {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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([
|
||||
|
||||
Reference in New Issue
Block a user