From f032da28788eca7ef559bddb00c84fc7b653ed8a Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 27 Nov 2024 14:55:52 +0000 Subject: [PATCH 01/35] chore: incrementing version number - v3.11.0 --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 76954ea502..9aba2d6f57 100644 --- a/install/package.json +++ b/install/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "3.10.3", + "version": "3.11.0", "homepage": "https://www.nodebb.org", "repository": { "type": "git", From 0333d263938aa7ea6ad7ad390d2b6531e43f1c6d Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 27 Nov 2024 14:55:53 +0000 Subject: [PATCH 02/35] chore: update changelog for v3.11.0 --- CHANGELOG.md | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9110eb824c..8b494cd652 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,227 @@ +#### v3.11.0 (2024-11-27) + +##### Chores + +* **i18n:** + * fallback strings for new resources: nodebb.admin-settings-reputation, nodebb.error (985e5e3d) + * fallback strings for new resources: nodebb.admin-manage-user-custom-fields, nodebb.error (174be398) + * fallback strings for new resources: nodebb.error (b676c220) + * fallback strings for new resources: nodebb.admin-manage-user-custom-fields (b89036cd) + * fallback strings for new resources: nodebb.admin-settings-uploads (e3ef858b) + * fallback strings for new resources: nodebb.admin-manage-users, nodebb.error (15e16704) + * fallback strings for new resources: nodebb.topic (9fd5ca27) + * fallback strings for new resources: nodebb.pages, nodebb.user (1c26048f) +* migrate admin/settings/social.json into admin/settings/general.json (206613dd) +* migrate admin/settings/languages.json into admin/settings/general.json (ab143b1d) +* migrate admin/settings/homepage.json into admin/settings/general.json (a7678185) +* combine admin/settings/guest.json language file into admin/settings/user.json (3f14373c) +* up themes (388a156d) +* up harmony (2324a5bf) +* up harmony (03cea237) +* up themes (2ec3d1af) +* up themes (965ca636) +* up persona (1a4a9d08) +* up peace (acd42c23) +* up peace (7179a280) +* up peace (bcf8dee2) +* up peace (524b2b76) +* up themes (4ad082b4) +* up peace (953ea609) +* up widgets (6a71fd24) +* up harmony (f13b7f8d) +* up persona (6f89bf6b) +* up persona (79c93c85) +* up themes (d63a828d) +* up themes (6aa8f1b6) +* up peace (a4d8baf3) +* up themes (24e9adf6) +* up persona (baff68b4) +* up peace (c4b50607) +* up lavender (c32c63aa) +* up lavender (66214bea) +* update tx config (4ce387b9) +* up themes (65f64eba) +* up themes (280e7613) +* up widgets (b13bd803) +* incrementing version number - v3.10.3 (57d54224) +* update changelog for v3.10.3 (83965385) +* up harmony (f6f1d906) +* incrementing version number - v3.10.2 (2f15f464) +* incrementing version number - v3.10.1 (cca3a644) +* up harmony (9426fd1a) +* incrementing version number - v3.10.0 (b60a9b4e) +* incrementing version number - v3.9.1 (f120c91c) +* incrementing version number - v3.9.0 (4880f32d) +* incrementing version number - v3.8.4 (4833f9a6) +* incrementing version number - v3.8.3 (97ce2c44) +* incrementing version number - v3.8.2 (72d91251) +* incrementing version number - v3.8.1 (527326f7) +* incrementing version number - v3.8.0 (e228a6eb) +* incrementing version number - v3.7.5 (6882894d) +* incrementing version number - v3.7.4 (6678744c) +* incrementing version number - v3.7.3 (2d62b6f6) +* incrementing version number - v3.7.2 (cc257e7e) +* incrementing version number - v3.7.1 (712365a5) +* incrementing version number - v3.7.0 (9a6153d7) +* incrementing version number - v3.6.7 (86a17e38) +* incrementing version number - v3.6.6 (6604bf37) +* incrementing version number - v3.6.5 (6c653625) +* incrementing version number - v3.6.4 (83d131b4) +* incrementing version number - v3.6.3 (fc7d2bfd) +* incrementing version number - v3.6.2 (0f577a57) +* incrementing version number - v3.6.1 (f1a69468) +* incrementing version number - v3.6.0 (4cdf85f8) +* incrementing version number - v3.5.3 (ed0e8783) +* incrementing version number - v3.5.2 (52fbb2da) +* incrementing version number - v3.5.1 (4c543488) +* incrementing version number - v3.5.0 (d06fb4f0) +* incrementing version number - v3.4.3 (5c984250) +* incrementing version number - v3.4.2 (3f0dac38) +* incrementing version number - v3.4.1 (01e69574) +* incrementing version number - v3.4.0 (fd9247c5) +* incrementing version number - v3.3.9 (5805e770) +* incrementing version number - v3.3.8 (a5603565) +* incrementing version number - v3.3.7 (b26f1744) +* incrementing version number - v3.3.6 (7fb38792) +* incrementing version number - v3.3.4 (a67f84ea) +* incrementing version number - v3.3.3 (f94d239b) +* incrementing version number - v3.3.2 (ec9dac97) +* incrementing version number - v3.3.1 (151cc68f) +* incrementing version number - v3.3.0 (fc1ad70f) +* incrementing version number - v3.2.3 (b06d3e63) +* incrementing version number - v3.2.2 (758ecfcd) +* incrementing version number - v3.2.1 (20145074) +* incrementing version number - v3.2.0 (9ecac38e) +* incrementing version number - v3.1.7 (0b4e81ab) +* incrementing version number - v3.1.6 (b3a3b130) +* incrementing version number - v3.1.5 (ec19343a) +* incrementing version number - v3.1.4 (2452783c) +* incrementing version number - v3.1.3 (3b4e9d3f) +* incrementing version number - v3.1.2 (40fa3489) +* incrementing version number - v3.1.1 (40250733) +* incrementing version number - v3.1.0 (0cb386bd) +* incrementing version number - v3.0.1 (26f6ea49) +* incrementing version number - v3.0.0 (224e08cd) +* **deps:** + * update commitlint monorepo to v19.6.0 (#12920) (151e0164) + * update postgres docker tag to v17.2 (#12931) (036f4564) + * update postgres docker tag to v17.1 (#12915) (0d0f9144) + * update dependency sass-embedded to v1.81.0 (#12914) (ff258028) + * update dependency sass-embedded to v1.80.6 (#12894) (37f877b3) + * update dependency sass-embedded to v1.80.5 (#12889) (383f332c) + * update dependency mocha to v10.8.2 (#12884) (d86bedf8) + * update coverallsapp/github-action action to v2.3.4 (#12867) (351bcdbf) + * update dependency sass-embedded to v1.80.4 (#12861) (be0c92ec) + * update dependency smtp-server to v3.13.6 (#12859) (a0804485) + * update coverallsapp/github-action action to v2.3.3 (#12854) (48b09f1d) + * update coverallsapp/github-action action to v2.3.2 (#12846) (c16192dc) + * update dependency sass-embedded to v1.79.5 (#12850) (6f227264) + * update dependency eslint-plugin-import to v2.31.0 (#12832) (cc2e0e9f) + * update redis docker tag to v7.4.1 (#12836) (e7cba341) + * update mongo docker tag to v8 (#12810) (2fd89558) + * update dependency sass-embedded to v1.79.4 (#12825) (24928b17) + * update postgres docker tag to v17 (#12829) (d7299f90) + +##### New Features + +* use displayname in chat system messages, closes #12937 (e6f78d25) +* move website/location fields into custom user fields (669c9c50) +* add pagination to groups page, api routes (49e0e1ab) +* add date and multiselect custom fields (9cf85ced) +* new language file for user custom fields (05fb8aa5) +* closes #12902, allow adding users as post editors (bc00df3c) +* added nn_NO, takk\! (b9eff72d) +* add read topics route (757d7101) + +##### Bug Fixes + +* update acp template to use new lang keys (bc5b91aa) +* spec, dont show registered-users, verified-users, unverified-users in manage groups (8605584f) +* #12927, give more right padding on FF (5b3b003d) +* dont show chat upload btn if maxFileSize is 0, #12926 (14125858) +* dont allow core user fields to be used as custom fields (836e8458) +* button to match category dropdown (5e9b7b44) +* filter undefined posts/topics (db291ecd) +* don't crash if post is undefined (d4770908) +* spec (d5c9c0ba) +* block search showing old matches (a9fc13dd) +* missing template (008ad1e3) +* naive checking to handle uploaded images whose filenames end with '-resized' (1268ed50) +* update copy to reflect real default value of 2000px for `resizeImageWidthThreshold` (4614958b) +* editor removal (977d80c1) +* add warning txt file for nn-NO (23b3a64a) +* incorrect folder syntax for nn_NO (396c7766) +* use postData.topic.title instead of topicData.title (d24bc5c5) +* another missing await (10a85e94) +* **deps:** + * update dependency sortablejs to v1.15.4 (#12934) (2db5b815) + * update dependency nodebb-plugin-2factor to v7.5.7 (#12930) (f9c4815a) + * update dependency @fortawesome/fontawesome-free to v6.7.1 (#12929) (80b4d10b) + * update dependency mongodb to v6.11.0 (#12932) (c3b42c85) + * update dependency @fortawesome/fontawesome-free to v6.7.0 (#12921) (a3042479) + * update dependency ace-builds to v1.36.5 (#12913) (68637633) + * update dependency sass to v1.81.0 (#12916) (ee91e516) + * update dependency cron to v3.2.1 (#12911) (42791287) + * update dependency postcss to v8.4.49 (#12910) (85f55695) + * update dependency winston to v3.17.0 (#12906) (87c276dd) + * update dependency postcss to v8.4.48 (#12907) (aa57b248) + * update dependency nodebb-theme-peace to v2.2.8 (#12901) (8af37a7d) + * update dependency cron to v3.1.9 (#12899) (87ec8637) + * update dependency ace-builds to v1.36.4 (#12898) (3aa0fa61) + * update dependency winston to v3.16.0 (#12896) (a4f75ca1) + * update dependency compression to v1.7.5 (#12890) (f5439d95) + * update dependency webpack to v5.96.1 (#12895) (3d847a5a) + * update dependency sass to v1.80.6 (#12892) (c5dd8b67) + * update dependency jquery-ui to v1.14.1 (#12891) (3fb6587a) + * update dependency nodebb-plugin-composer-default to v10.2.42 (#12888) (2cb2ac3a) + * update dependency cron to v3.1.8 (#12881) (8ae2f503) + * update dependency chart.js to v4.4.6 (#12876) (89bd1a24) + * update dependency nodemailer to v6.9.16 (#12874) (51cb249e) + * update dependency pg-cursor to v2.12.1 (#12870) (e3203b66) + * update dependency pg to v8.13.1 (#12869) (b628013d) + * update socket.io packages to v4.8.1 (#12871) (cdd9caa7) + * update dependency nodebb-theme-harmony to v1.2.77 (#12868) (d30e1f91) + * update dependency mongodb to v6.10.0 (#12862) (6da24583) + * update dependency ace-builds to v1.36.3 (#12860) (8d8243c4) + * update dependency sass to v1.80.4 (#12855) (80034ae8) + * update socket.io packages to v4.8.0 (#12815) (4788e2a3) + * update dependency chart.js to v4.4.5 (#12852) (c504b49f) + * update dependency workerpool to v9.2.0 (#12851) (8dfb2237) + * update dependency sass to v1.79.5 (#12847) (ab859aec) + * update dependency cookie-parser to v1.4.7 (#12842) (526faf07) + * update dependency express to v4.21.1 (#12843) (0e7f11bd) + * update dependency express-session to v1.18.1 (#12844) (38c1072f) + * update dependency sanitize-html to v2.13.1 (#12839) (5159552d) + * update dependency winston to v3.15.0 (#12840) (29826cf2) + * update dependency webpack to v5.95.0 (#12828) (55faa8a2) + * update dependency sass to v1.79.4 (#12826) (376ac905) + * update dependency helmet to v7.2.0 (#12827) (5acf0398) + * update dependency nodebb-theme-harmony to v1.2.71 (#12820) (b1993ff0) + +##### Other Changes + +* remove unused utils (0e4fc531) +* remove unused utils (b6a79365) +* //github.com/NodeBB/NodeBB/issues/12824 (c4a60dbb) + +##### Refactors + +* shorter check for showfullname (6ebff2e1) +* remove unused uids (20da7148) +* no category sharing for a long time (6af5cef7) +* move flags into core (3dff083d) +* add some margin bottom to bs tags (40758b32) +* post queue btn and dropdown (038fb71e) +* search logic to use switch..case (bd76ccf0) + +##### Tests + +* fix tests (173c604a) +* fix crash due to excludeGroups (61d43ee1) +* fix spec (70d99501) +* fix spec (c586854a) +* update spec on plugins (f9178a39) + #### v3.10.3 (2024-10-23) ##### Chores From 55ad7af806d01a3a5acc217e290f9c1d383bdbb9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:41:22 -0500 Subject: [PATCH 03/35] chore(deps): update dependency mocha to v11 (#12954) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 66ebb76e2e..dcd5d57b9e 100644 --- a/install/package.json +++ b/install/package.json @@ -168,7 +168,7 @@ "husky": "8.0.3", "jsdom": "25.0.1", "lint-staged": "15.2.10", - "mocha": "10.8.2", + "mocha": "11.0.1", "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5", "nyc": "17.1.0", From 122d3841cc04d34698e4d9980bc1c66fe60cdfdc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:41:34 -0500 Subject: [PATCH 04/35] fix(deps): update dependency webpack to v5.97.1 (#12953) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index dcd5d57b9e..f27279a04a 100644 --- a/install/package.json +++ b/install/package.json @@ -146,7 +146,7 @@ "toobusy-js": "0.5.1", "tough-cookie": "5.0.0", "validator": "13.12.0", - "webpack": "5.96.1", + "webpack": "5.97.1", "webpack-merge": "6.0.1", "winston": "3.17.0", "workerpool": "9.2.0", From 3bd447be081c3884f0e37802b4c305a739433b98 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:41:50 -0500 Subject: [PATCH 05/35] fix(deps): update dependency sass to v1.82.0 (#12952) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f27279a04a..3d21c63d32 100644 --- a/install/package.json +++ b/install/package.json @@ -128,7 +128,7 @@ "rss": "1.2.2", "rtlcss": "4.3.0", "sanitize-html": "2.13.1", - "sass": "1.81.0", + "sass": "1.82.0", "semver": "7.6.3", "serve-favicon": "2.5.0", "sharp": "0.32.6", From 6e2b33b7c7b6a9777f20c7ff474a6292704574a9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:41:58 -0500 Subject: [PATCH 06/35] chore(deps): update dependency sass-embedded to v1.82.0 (#12951) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 3d21c63d32..0f334f11a8 100644 --- a/install/package.json +++ b/install/package.json @@ -175,7 +175,7 @@ "smtp-server": "3.13.6" }, "optionalDependencies": { - "sass-embedded": "1.81.0" + "sass-embedded": "1.82.0" }, "resolutions": { "*/jquery": "3.7.1" From 300ca70476e05a4cf4554133c89a098277f73afd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:42:17 -0500 Subject: [PATCH 07/35] fix(deps): update dependency chart.js to v4.4.7 (#12950) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 0f334f11a8..f6fbeb6b06 100644 --- a/install/package.json +++ b/install/package.json @@ -49,7 +49,7 @@ "bootstrap": "5.3.3", "bootswatch": "5.3.3", "chalk": "4.1.2", - "chart.js": "4.4.6", + "chart.js": "4.4.7", "cli-graph": "3.2.2", "clipboard": "2.0.11", "colors": "1.4.0", From 59df4f39be1f36f9a25169b0d137e535ae452830 Mon Sep 17 00:00:00 2001 From: "Matthew M." <33269887+matt4499@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:38:59 -0600 Subject: [PATCH 08/35] Update docker-compose.yml (#12949) Remove version attribute - obsolete --- docker-compose.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f12392abd1..709cd69d03 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: nodebb: build: . From 26026fb2d78a7426aa52f9abe57855536a763f81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 6 Dec 2024 15:43:34 -0500 Subject: [PATCH 09/35] fix: escape about me on user flags --- src/flags.js | 1 + src/views/flags/detail.tpl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flags.js b/src/flags.js index 00bce1d9bd..be0f849244 100644 --- a/src/flags.js +++ b/src/flags.js @@ -663,6 +663,7 @@ Flags.canFlag = async function (type, id, uid, skipLimitCheck = false) { Flags.getTarget = async function (type, id, uid) { if (type === 'user') { const userData = await user.getUserData(id); + userData.aboutme = validator.escape(String(userData.aboutme)); return userData && userData.uid ? userData : {}; } if (type === 'post') { diff --git a/src/views/flags/detail.tpl b/src/views/flags/detail.tpl index 6c8cd657f3..c1e39af6ac 100644 --- a/src/views/flags/detail.tpl +++ b/src/views/flags/detail.tpl @@ -123,7 +123,7 @@ {{{ end }}} {{{ if type_bool.user }}} -
+ From 4e69bff72fd04779064d37e46a43080e6c328adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 6 Dec 2024 15:43:34 -0500 Subject: [PATCH 10/35] fix: escape about me on user flags --- src/flags.js | 1 + src/views/flags/detail.tpl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flags.js b/src/flags.js index 00bce1d9bd..be0f849244 100644 --- a/src/flags.js +++ b/src/flags.js @@ -663,6 +663,7 @@ Flags.canFlag = async function (type, id, uid, skipLimitCheck = false) { Flags.getTarget = async function (type, id, uid) { if (type === 'user') { const userData = await user.getUserData(id); + userData.aboutme = validator.escape(String(userData.aboutme)); return userData && userData.uid ? userData : {}; } if (type === 'post') { diff --git a/src/views/flags/detail.tpl b/src/views/flags/detail.tpl index 6c8cd657f3..c1e39af6ac 100644 --- a/src/views/flags/detail.tpl +++ b/src/views/flags/detail.tpl @@ -123,7 +123,7 @@ {{{ end }}} {{{ if type_bool.user }}} -
+ From 55a07bcbc94b4960eab8b3a2466f48d96e539804 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:55:34 -0500 Subject: [PATCH 11/35] fix(deps): update dependency express to v4.21.2 (#12955) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f6fbeb6b06..85b14e15f5 100644 --- a/install/package.json +++ b/install/package.json @@ -68,7 +68,7 @@ "daemon": "1.1.0", "diff": "7.0.0", "esbuild": "0.24.0", - "express": "4.21.1", + "express": "4.21.2", "express-session": "1.18.1", "express-useragent": "1.0.15", "fetch-cookie": "3.0.1", From a72c067fd0fac3623327ff33c06fef71f5a5949d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 6 Dec 2024 16:35:31 -0500 Subject: [PATCH 12/35] chore: up peace --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 85b14e15f5..ee9bc5f517 100644 --- a/install/package.json +++ b/install/package.json @@ -109,7 +109,7 @@ "nodebb-rewards-essentials": "1.0.0", "nodebb-theme-harmony": "1.2.88", "nodebb-theme-lavender": "7.1.16", - "nodebb-theme-peace": "2.2.23", + "nodebb-theme-peace": "2.2.27", "nodebb-theme-persona": "13.3.56", "nodebb-widget-essentials": "7.0.31", "nodemailer": "6.9.16", From 3a7e9733a4d47e6cdcc8c341774629e63acb117d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 7 Dec 2024 13:14:51 -0500 Subject: [PATCH 13/35] chore: up spam-be-gone --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a60734d844..c571855be6 100644 --- a/install/package.json +++ b/install/package.json @@ -105,7 +105,7 @@ "nodebb-plugin-markdown": "12.2.8", "nodebb-plugin-mentions": "4.4.5", "nodebb-plugin-ntfy": "1.7.7", - "nodebb-plugin-spam-be-gone": "2.2.2", + "nodebb-plugin-spam-be-gone": "2.3.0", "nodebb-rewards-essentials": "1.0.0", "nodebb-theme-harmony": "1.2.88", "nodebb-theme-lavender": "7.1.16", From c8a38667bb038cda228e39cdc0a91b57a515a51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 8 Dec 2024 17:53:48 -0500 Subject: [PATCH 14/35] fix: closes #12957, don't overflow thumbs modal if filename is too long --- src/views/modals/topic-thumbs.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/modals/topic-thumbs.tpl b/src/views/modals/topic-thumbs.tpl index ec2366080d..ead862457c 100644 --- a/src/views/modals/topic-thumbs.tpl +++ b/src/views/modals/topic-thumbs.tpl @@ -9,7 +9,7 @@

- {./name} + {./name}

From e6bdbb6b2393c8c64acd2ee210b325d51fa73181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 09:56:30 -0500 Subject: [PATCH 15/35] feat: add some missing canonical tags, closes #12961 --- src/controllers/accounts/follow.js | 11 +++++++++++ src/controllers/accounts/groups.js | 10 ++++++++++ src/controllers/accounts/posts.js | 11 +++++++++++ src/controllers/accounts/profile.js | 10 ++++++++++ src/controllers/groups.js | 16 ++++++++++++++++ src/controllers/tags.js | 9 +++++++++ src/controllers/users.js | 11 +++++++++++ 7 files changed, 78 insertions(+) diff --git a/src/controllers/accounts/follow.js b/src/controllers/accounts/follow.js index 7a28374582..dac4902701 100644 --- a/src/controllers/accounts/follow.js +++ b/src/controllers/accounts/follow.js @@ -1,11 +1,15 @@ 'use strict'; +const nconf = require('nconf'); + const user = require('../../user'); const helpers = require('../helpers'); const pagination = require('../../pagination'); const followController = module.exports; +const url = nconf.get('url'); + followController.getFollowing = async function (req, res, next) { await getFollow('account/following', 'following', req, res, next); }; @@ -39,5 +43,12 @@ async function getFollow(tpl, name, req, res, next) { payload.breadcrumbs = helpers.buildBreadcrumbs([{ text: username, url: `/user/${userslug}` }, { text: `[[user:${name}]]` }]); + res.locals.linkTags = [ + { + rel: 'canonical', + href: `${url}${req.url.replace(/^\/api/, '')}`, + }, + ]; + res.render(tpl, payload); } diff --git a/src/controllers/accounts/groups.js b/src/controllers/accounts/groups.js index 3a9d66243e..fbe9a39407 100644 --- a/src/controllers/accounts/groups.js +++ b/src/controllers/accounts/groups.js @@ -1,11 +1,15 @@ 'use strict'; +const nconf = require('nconf'); + const user = require('../../user'); const groups = require('../../groups'); const helpers = require('../helpers'); const groupsController = module.exports; +const url = nconf.get('url'); + groupsController.get = async function (req, res) { const { username, userslug } = await user.getUserFields(res.locals.uid, ['username', 'userslug']); @@ -21,5 +25,11 @@ groupsController.get = async function (req, res) { payload.groups = groupsData; payload.title = `[[pages:account/groups, ${username}]]`; payload.breadcrumbs = helpers.buildBreadcrumbs([{ text: username, url: `/user/${userslug}` }, { text: '[[global:header.groups]]' }]); + res.locals.linkTags = [ + { + rel: 'canonical', + href: `${url}${req.url.replace(/^\/api/, '')}`, + }, + ]; res.render('account/groups', payload); }; diff --git a/src/controllers/accounts/posts.js b/src/controllers/accounts/posts.js index adb8fbffc8..f36834ef0e 100644 --- a/src/controllers/accounts/posts.js +++ b/src/controllers/accounts/posts.js @@ -1,5 +1,7 @@ 'use strict'; +const nconf = require('nconf'); + const db = require('../../database'); const user = require('../../user'); const posts = require('../../posts'); @@ -13,6 +15,8 @@ const utils = require('../../utils'); const postsController = module.exports; +const url = nconf.get('url'); + const templateToData = { 'account/bookmarks': { type: 'posts', @@ -240,6 +244,13 @@ async function getPostsFromUserSet(template, req, res) { option.selected = option.url.includes(`sort=${req.query.sort}`); }); + res.locals.linkTags = [ + { + rel: 'canonical', + href: `${url}${req.url.replace(/^\/api/, '')}`, + }, + ]; + res.render(template, payload); } diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js index e24415794d..0f2cf3cf9c 100644 --- a/src/controllers/accounts/profile.js +++ b/src/controllers/accounts/profile.js @@ -1,6 +1,7 @@ 'use strict'; const _ = require('lodash'); +const nconf = require('nconf'); const db = require('../../database'); const user = require('../../user'); @@ -14,6 +15,8 @@ const utils = require('../../utils'); const profileController = module.exports; +const url = nconf.get('url'); + profileController.get = async function (req, res, next) { const { userData } = res.locals; if (!userData) { @@ -151,4 +154,11 @@ function addMetaTags(res, userData) { } ); } + + res.locals.linkTags = [ + { + rel: 'canonical', + href: `${url}/user/${userData.userslug}`, + }, + ]; } diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 76c1b00f97..4638384b6e 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -12,6 +12,8 @@ const privileges = require('../privileges'); const groupsController = module.exports; +const url = nconf.get('url'); + groupsController.list = async function (req, res) { const sort = req.query.sort || 'alpha'; const page = parseInt(req.query.page, 10) || 1; @@ -20,6 +22,13 @@ groupsController.list = async function (req, res) { getGroups(req, sort, page), ]); + res.locals.linkTags = [ + { + rel: 'canonical', + href: `${url}${req.url.replace(/^\/api/, '')}`, + }, + ]; + res.render('groups/list', { groups: groupData, allowGroupCreation: allowGroupCreation, @@ -101,6 +110,13 @@ groupsController.details = async function (req, res, next) { return next(); } + res.locals.linkTags = [ + { + rel: 'canonical', + href: `${url}/groups/${lowercaseSlug}`, + }, + ]; + res.render('groups/details', { title: `[[pages:group, ${groupData.displayName}]]`, group: groupData, diff --git a/src/controllers/tags.js b/src/controllers/tags.js index 392ff9201e..01c91f345c 100644 --- a/src/controllers/tags.js +++ b/src/controllers/tags.js @@ -14,6 +14,8 @@ const helpers = require('./helpers'); const tagsController = module.exports; +const url = nconf.get('url'); + tagsController.getTag = async function (req, res) { const tag = validator.escape(utils.cleanUpTag(req.params.tag, meta.config.maximumTagLength)); const page = parseInt(req.query.page, 10) || 1; @@ -89,6 +91,13 @@ tagsController.getTags = async function (req, res) { topics.getCategoryTagsData(cids, 0, 99), ]); + res.locals.linkTags = [ + { + rel: 'canonical', + href: `${url}/tags`, + }, + ]; + res.render('tags', { tags: tags.filter(Boolean), displayTagSearch: canSearch, diff --git a/src/controllers/users.js b/src/controllers/users.js index 41194e6c82..e2deb1d93b 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -1,5 +1,7 @@ 'use strict'; +const nconf = require('nconf'); + const user = require('../user'); const meta = require('../meta'); @@ -12,6 +14,8 @@ const utils = require('../utils'); const usersController = module.exports; +const url = nconf.get('url'); + usersController.index = async function (req, res, next) { const section = req.query.section || 'joindate'; const sectionToController = { @@ -206,6 +210,13 @@ async function render(req, res, data) { data['reputation:disabled'] = meta.config['reputation:disabled']; + res.locals.linkTags = [ + { + rel: 'canonical', + href: `${url}${req.url.replace(/^\/api/, '')}`, + }, + ]; + res.append('X-Total-Count', data.userCount); res.render('users', data); } From 4568ec3e04a290f7e92618fa77d918c1457dde58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 10:00:03 -0500 Subject: [PATCH 16/35] fix: closes #12962, fix js error for guests on /users dont focus input on mobile --- public/src/client/users.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/public/src/client/users.js b/public/src/client/users.js index 47c16f9387..45ea32ea40 100644 --- a/public/src/client/users.js +++ b/public/src/client/users.js @@ -32,13 +32,16 @@ define('forum/users', [ // Populate box with query if present const searchEl = document.getElementById('search-user'); - const search = new URLSearchParams(document.location.search); - const query = search.get('query'); - if (query) { - searchEl.value = query; + if (searchEl) { + const search = new URLSearchParams(document.location.search); + const query = search.get('query'); + if (query) { + searchEl.value = query; + } + if (!utils.isMobile()) { + searchEl.focus(); + } } - - searchEl.focus(); }; function doSearch() { From e532dcb46c4724e1b4f2e879ac98248788d2b44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 10:46:45 -0500 Subject: [PATCH 17/35] chore: up themes --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index c571855be6..69e40d598d 100644 --- a/install/package.json +++ b/install/package.json @@ -109,8 +109,8 @@ "nodebb-rewards-essentials": "1.0.0", "nodebb-theme-harmony": "1.2.88", "nodebb-theme-lavender": "7.1.16", - "nodebb-theme-peace": "2.2.27", - "nodebb-theme-persona": "13.3.56", + "nodebb-theme-peace": "2.2.28", + "nodebb-theme-persona": "13.3.57", "nodebb-widget-essentials": "7.0.31", "nodemailer": "6.9.16", "nprogress": "0.2.0", From fe811537e93532e21ff4e6d77190271a032c5494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 14:40:49 -0500 Subject: [PATCH 18/35] refactor: remove "password" in comments --- src/api/users.js | 5 ++--- src/cli/setup.js | 3 +-- src/install.js | 7 +------ src/middleware/admin.js | 1 - src/socket.io/user.js | 1 - src/user/data.js | 1 - src/user/index.js | 2 +- src/user/reset.js | 1 - 8 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/api/users.js b/src/api/users.js index 3897613342..5b7e35d254 100644 --- a/src/api/users.js +++ b/src/api/users.js @@ -67,8 +67,8 @@ usersAPI.update = async function (caller, data) { privileges.users.canEdit(caller.uid, data.uid), ]); - // Changing own email/username requires password confirmation - if (data.hasOwnProperty('email') || data.hasOwnProperty('username')) { + const isChangingEmailOrUsername = data.hasOwnProperty('email') || data.hasOwnProperty('username'); + if (isChangingEmailOrUsername) { await isPrivilegedOrSelfAndPasswordMatch(caller, data); } @@ -547,7 +547,6 @@ async function processDeletion({ uid, method, password, caller }) { throw new Error('[[error:no-privileges]]'); } - // Self-deletions require a password const hasPassword = await user.hasPassword(uid); if (isSelf && hasPassword) { const ok = await user.isPasswordCorrect(uid, password, caller.ip); diff --git a/src/cli/setup.js b/src/cli/setup.js index 859f674a9c..67b958ed95 100644 --- a/src/cli/setup.js +++ b/src/cli/setup.js @@ -51,8 +51,7 @@ async function setup(initConfig) { } console.log('NodeBB Setup Completed. Run "./nodebb start" to manually start your NodeBB server.'); - // If I am a child process, notify the parent of the returned data before exiting (useful for notifying - // hosts of auto-generated username/password during headless setups) + // If I am a child process, notify the parent of the returned data before exiting (useful for notifying hosts during headless setups) if (process.send) { process.send(data); } diff --git a/src/install.js b/src/install.js index 89b40d7b39..54ea7a325f 100644 --- a/src/install.js +++ b/src/install.js @@ -370,26 +370,21 @@ async function createAdmin() { } async function retryPassword(originalResults) { - // Ask only the password questions const results = await prompt.get(passwordQuestions); - // Update the original data with newly collected password originalResults.password = results.password; originalResults['password:confirm'] = results['password:confirm']; - // Send back to success to handle return await success(originalResults); } - // Add the password questions questions = questions.concat(passwordQuestions); if (!install.values) { const results = await prompt.get(questions); return await success(results); } - // If automated setup did not provide a user password, generate one, - // it will be shown to the user upon setup completion + if (!install.values.hasOwnProperty('admin:password') && !nconf.get('admin:password')) { console.log('Password was not provided during automated setup, generating one...'); password = utils.generateUUID().slice(0, 8); diff --git a/src/middleware/admin.js b/src/middleware/admin.js index bf89079103..84d34dfbd0 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -47,7 +47,6 @@ middleware.checkPrivileges = helpers.try(async (req, res, next) => { } } - // If user does not have password const hasPassword = await user.hasPassword(req.uid); if (!hasPassword) { return next(); diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 51e5dc9f71..c20c545f8a 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -24,7 +24,6 @@ require('./user/status')(SocketUser); require('./user/picture')(SocketUser); require('./user/registration')(SocketUser); -// Password Reset SocketUser.reset = {}; SocketUser.reset.send = async function (socket, email) { diff --git a/src/user/data.js b/src/user/data.js index 47975ea99a..96ddfc51fe 100644 --- a/src/user/data.js +++ b/src/user/data.js @@ -82,7 +82,6 @@ module.exports = function (User) { if (!fields.length) { fields = results.whitelist; } else { - // Never allow password retrieval via this method fields = fields.filter(value => value !== 'password'); } diff --git a/src/user/index.js b/src/user/index.js index 5922fea7b7..eaba1dbb32 100644 --- a/src/user/index.js +++ b/src/user/index.js @@ -244,7 +244,7 @@ User.addInterstitials = function (callback) { plugins.hooks.register('core', { hook: 'filter:register.interstitial', method: [ - User.interstitials.email, // Email address (for password reset + digest) + User.interstitials.email, // Email address User.interstitials.gdpr, // GDPR information collection/processing consent + email consent User.interstitials.tou, // Forum Terms of Use ], diff --git a/src/user/reset.js b/src/user/reset.js index 9a6d6330ff..d2782c6dc0 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -108,7 +108,6 @@ UserReset.commit = async function (code, password) { 'password:shaWrapped': 1, }; - // don't verify email if password reset is due to expiry const isPasswordExpired = userData.passwordExpiry && userData.passwordExpiry < Date.now(); if (!isPasswordExpired) { data['email:confirmed'] = 1; From c69765e305f3788f44cc1d1213f3bb03692f6a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 14:44:05 -0500 Subject: [PATCH 19/35] lint: long line --- src/cli/setup.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/setup.js b/src/cli/setup.js index 67b958ed95..511dc81e73 100644 --- a/src/cli/setup.js +++ b/src/cli/setup.js @@ -51,7 +51,8 @@ async function setup(initConfig) { } console.log('NodeBB Setup Completed. Run "./nodebb start" to manually start your NodeBB server.'); - // If I am a child process, notify the parent of the returned data before exiting (useful for notifying hosts during headless setups) + // If I am a child process, notify the parent of the returned data before exiting + // (useful for notifying hosts during headless setups) if (process.send) { process.send(data); } From 9d2af7e10c74a83fe2b5ed3167de5838d6ed49d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 18:18:02 -0500 Subject: [PATCH 20/35] refactor: replace math.random with crypto --- src/categories/create.js | 2 +- src/controllers/404.js | 3 ++- src/database/mongo/sets.js | 3 ++- src/meta/cacheBuster.js | 6 +++++- src/password.js | 4 +++- src/socket.io/user.js | 4 ++-- src/utils.js | 10 ++++++++++ test/utils.js | 15 ++++++++++++++- 8 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/categories/create.js b/src/categories/create.js index c4aa403425..d8f3e4a65c 100644 --- a/src/categories/create.js +++ b/src/categories/create.js @@ -149,7 +149,7 @@ module.exports = function (Categories) { Categories.assignColours = function () { const backgrounds = ['#AB4642', '#DC9656', '#F7CA88', '#A1B56C', '#86C1B9', '#7CAFC2', '#BA8BAF', '#A16946']; const text = ['#ffffff', '#ffffff', '#333333', '#ffffff', '#333333', '#ffffff', '#ffffff', '#ffffff']; - const index = Math.floor(Math.random() * backgrounds.length); + const index = utils.secureRandom(0, backgrounds.length - 1); return [backgrounds[index], text[index]]; }; diff --git a/src/controllers/404.js b/src/controllers/404.js index 33f04f142e..becc206e76 100644 --- a/src/controllers/404.js +++ b/src/controllers/404.js @@ -8,6 +8,7 @@ const meta = require('../meta'); const plugins = require('../plugins'); const middleware = require('../middleware'); const helpers = require('../middleware/helpers'); +const { secureRandom } = require('../utils'); exports.handle404 = helpers.try(async (req, res) => { const relativePath = nconf.get('relative_path'); @@ -64,6 +65,6 @@ exports.send404 = helpers.try(async (req, res) => { path: validator.escape(path), title: '[[global:404.title]]', bodyClass: helpers.buildBodyClass(req, res), - icon: icons[Math.floor(Math.random() * icons.length)], + icon: icons[secureRandom(0, icons.length - 1)], }); }); diff --git a/src/database/mongo/sets.js b/src/database/mongo/sets.js index 3f110b79f9..0c84a0f210 100644 --- a/src/database/mongo/sets.js +++ b/src/database/mongo/sets.js @@ -3,6 +3,7 @@ module.exports = function (module) { const _ = require('lodash'); const helpers = require('./helpers'); + const { secureRandom } = require('../../utils'); module.setAdd = async function (key, value) { if (!Array.isArray(value)) { @@ -200,7 +201,7 @@ module.exports = function (module) { return; } - const randomIndex = Math.floor(Math.random() * data.members.length); + const randomIndex = secureRandom(0, data.members.length - 1); const value = data.members[randomIndex]; await module.setRemove(data._key, value); return value; diff --git a/src/meta/cacheBuster.js b/src/meta/cacheBuster.js index 58129ff2f8..d1e4d2d239 100644 --- a/src/meta/cacheBuster.js +++ b/src/meta/cacheBuster.js @@ -11,7 +11,11 @@ let cached; // cache buster is an 11-character, lowercase, alphanumeric string function generate() { - return (Math.random() * 1e18).toString(32).slice(0, 11); + const crypto = require('crypto'); + const length = 11; + const generated = crypto.randomBytes(Math.ceil(length / 2)) + .toString('hex').slice(0, length); + return generated; } exports.write = async function write() { diff --git a/src/password.js b/src/password.js index 7c0d01931c..6f9617f6ab 100644 --- a/src/password.js +++ b/src/password.js @@ -29,7 +29,9 @@ async function getFakeHash() { if (fakeHashCache) { return fakeHashCache; } - fakeHashCache = await exports.hash(12, Math.random().toString()); + const length = 18; + fakeHashCache = crypto.randomBytes(Math.ceil(length / 2)) + .toString('hex').slice(0, length); return fakeHashCache; } diff --git a/src/socket.io/user.js b/src/socket.io/user.js index c20c545f8a..48b491ab43 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -46,10 +46,10 @@ SocketUser.reset.send = async function (socket, email) { try { await user.reset.send(email); await logEvent('[[success:success]]'); - await sleep(2500 + ((Math.random() * 500) - 250)); + await sleep(2500 + (utils.secureRandom(0, 500) - 250)); } catch (err) { await logEvent(err.message); - await sleep(2500 + ((Math.random() * 500) - 250)); + await sleep(2500 + (utils.secureRandom(0, 500) - 250)); const internalErrors = ['[[error:invalid-email]]']; if (!internalErrors.includes(err.message)) { throw err; diff --git a/src/utils.js b/src/utils.js index fb59865f69..6600b855ce 100644 --- a/src/utils.js +++ b/src/utils.js @@ -31,6 +31,16 @@ utils.generateUUID = function () { return rnd.join('-'); }; +utils.secureRandom = function (low, high) { + if (low > high) { + throw new Error("The 'low' parameter must be less than or equal to the 'high' parameter."); + } + const randomBuffer = crypto.randomBytes(4); + const randomInt = randomBuffer.readUInt32BE(0); + const range = high - low + 1; + return low + (randomInt % range); +}; + utils.getSass = function () { try { const sass = require('sass-embedded'); diff --git a/test/utils.js b/test/utils.js index dbf397e995..370c05d298 100644 --- a/test/utils.js +++ b/test/utils.js @@ -102,7 +102,7 @@ describe('Utility Methods', () => { }); }); - describe('UUID generation', () => { + describe('UUID generation / secureRandom', () => { it('return unique random value every time', () => { delete require.cache[require.resolve('../src/utils')]; const { generateUUID } = require('../src/utils'); @@ -110,6 +110,19 @@ describe('Utility Methods', () => { const uuid2 = generateUUID(); assert.notEqual(uuid1, uuid2, 'matches'); }); + + it('should return a random number between 1-10 inclusive', () => { + const { secureRandom } = require('../src/utils'); + const r1 = secureRandom(1, 10); + assert(r1 >= 1); + assert(r1 <= 10); + }); + + it('should always return 3', () => { + const { secureRandom } = require('../src/utils') + const r1 = secureRandom(3, 3); + assert.strictEqual(r1, 3); + }); }); describe('cleanUpTag', () => { From 0495842faebaef71713963ce4980051238b7f234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 18:25:31 -0500 Subject: [PATCH 21/35] lint: missing semi --- test/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils.js b/test/utils.js index 370c05d298..2d3edb7ff0 100644 --- a/test/utils.js +++ b/test/utils.js @@ -119,7 +119,7 @@ describe('Utility Methods', () => { }); it('should always return 3', () => { - const { secureRandom } = require('../src/utils') + const { secureRandom } = require('../src/utils'); const r1 = secureRandom(3, 3); assert.strictEqual(r1, 3); }); From 76caa92c0b6b76e901671f133a5352231d016518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 18:35:43 -0500 Subject: [PATCH 22/35] refactor: only send required fields in query --- src/controllers/admin/dashboard.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/admin/dashboard.js b/src/controllers/admin/dashboard.js index a8930e35f4..405a239aaf 100644 --- a/src/controllers/admin/dashboard.js +++ b/src/controllers/admin/dashboard.js @@ -275,7 +275,7 @@ dashboardController.getLogins = async (req, res) => { res.render('admin/dashboard/logins', { set: 'logins', - query: req.query, + query: _.pick(req.query, ['units', 'until', 'count']), stats, summary, sessions, @@ -303,7 +303,7 @@ dashboardController.getUsers = async (req, res) => { res.render('admin/dashboard/users', { set: 'registrations', - query: req.query, + query: _.pick(req.query, ['units', 'until', 'count']), stats, summary, users, @@ -330,7 +330,7 @@ dashboardController.getTopics = async (req, res) => { res.render('admin/dashboard/topics', { set: 'topics', - query: req.query, + query: _.pick(req.query, ['units', 'until', 'count']), stats, summary, topics: topicData, From c25fd40ae5e391ebd75f5f0f524cf8b1d2ae481b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 18:47:26 -0500 Subject: [PATCH 23/35] fix: race condition that results in 2x localReset call the same process --- src/cache/lru.js | 12 +++++++++--- src/cache/ttl.js | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/cache/lru.js b/src/cache/lru.js index fc6eb69147..2af778b23d 100644 --- a/src/cache/lru.js +++ b/src/cache/lru.js @@ -2,6 +2,8 @@ module.exports = function (opts) { const { LRUCache } = require('lru-cache'); + const os = require('os'); + const pubsub = require('../pubsub'); // lru-cache@7 deprecations @@ -91,7 +93,9 @@ module.exports = function (opts) { cache.delete = cache.del; cache.reset = function () { - pubsub.publish(`${cache.name}:lruCache:reset`); + pubsub.publish(`${cache.name}:lruCache:reset`, { + id: `${os.hostname()}:${process.pid}`, + }); localReset(); }; cache.clear = cache.reset; @@ -102,8 +106,10 @@ module.exports = function (opts) { cache.misses = 0; } - pubsub.on(`${cache.name}:lruCache:reset`, () => { - localReset(); + pubsub.on(`${cache.name}:lruCache:reset`, ({ id }) => { + if (id !== `${os.hostname()}:${process.pid}`) { + localReset(); + } }); pubsub.on(`${cache.name}:lruCache:del`, (keys) => { diff --git a/src/cache/ttl.js b/src/cache/ttl.js index 292c76fdc7..818289da00 100644 --- a/src/cache/ttl.js +++ b/src/cache/ttl.js @@ -2,6 +2,8 @@ module.exports = function (opts) { const TTLCache = require('@isaacs/ttlcache'); + const os = require('os'); + const pubsub = require('../pubsub'); const ttlCache = new TTLCache(opts); @@ -72,7 +74,9 @@ module.exports = function (opts) { cache.delete = cache.del; cache.reset = function () { - pubsub.publish(`${cache.name}:ttlCache:reset`); + pubsub.publish(`${cache.name}:ttlCache:reset`, { + id: `${os.hostname()}:${process.pid}`, + }); localReset(); }; cache.clear = cache.reset; @@ -83,8 +87,10 @@ module.exports = function (opts) { cache.misses = 0; } - pubsub.on(`${cache.name}:ttlCache:reset`, () => { - localReset(); + pubsub.on(`${cache.name}:ttlCache:reset`, ({ id }) => { + if (id !== `${os.hostname()}:${process.pid}`) { + localReset(); + } }); pubsub.on(`${cache.name}:ttlCache:del`, (keys) => { From bb0ff6d60219ada61229d3d8cee828aa1cb60a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 19:07:46 -0500 Subject: [PATCH 24/35] refactor: explicit settings/appearance routes --- src/controllers/admin/appearance.js | 14 ++- src/controllers/admin/settings.js | 169 +++++++++++++++++++--------- src/routes/admin.js | 24 +++- 3 files changed, 141 insertions(+), 66 deletions(-) diff --git a/src/controllers/admin/appearance.js b/src/controllers/admin/appearance.js index 5bcfa5321e..a1384a4185 100644 --- a/src/controllers/admin/appearance.js +++ b/src/controllers/admin/appearance.js @@ -2,8 +2,14 @@ const appearanceController = module.exports; -appearanceController.get = function (req, res) { - const term = req.params.term ? req.params.term : 'themes'; - - res.render(`admin/appearance/${term}`, {}); +appearanceController.themes = function (req, res) { + res.render(`admin/appearance/themes`, {}); +}; + +appearanceController.skins = function (req, res) { + res.render(`admin/appearance/skins`, {}); +}; + +appearanceController.customise = function (req, res) { + res.render(`admin/appearance/customise`, {}); }; diff --git a/src/controllers/admin/settings.js b/src/controllers/admin/settings.js index 61e8a6fb2d..9b891aa139 100644 --- a/src/controllers/admin/settings.js +++ b/src/controllers/admin/settings.js @@ -16,64 +16,20 @@ const translator = require('../../translator'); const settingsController = module.exports; -settingsController.get = async function (req, res) { - const term = req.params.term || 'general'; - const payload = { - title: `[[admin/menu:settings/${term}]]`, - }; - if (term === 'general') { - payload.routes = await helpers.getHomePageRoutes(req.uid); - payload.postSharing = await social.getPostSharing(); - const languageData = await languages.list(); - languageData.forEach((language) => { - language.selected = language.code === meta.config.defaultLang; - }); - payload.languages = languageData; - payload.autoDetectLang = meta.config.autoDetectLang; - } - res.render(`admin/settings/${term}`, payload); -}; - -settingsController.email = async (req, res) => { - const emails = await emailer.getTemplates(meta.config); - - res.render('admin/settings/email', { - title: '[[admin/menu:settings/email]]', - emails: emails, - sendable: emails.filter(e => !e.path.includes('_plaintext') && !e.path.includes('partials')).map(tpl => tpl.path), - services: emailer.listServices(), +settingsController.general = async (req, res) => { + const routes = await helpers.getHomePageRoutes(req.uid); + const postSharing = await social.getPostSharing(); + const languageData = await languages.list(); + languageData.forEach((language) => { + language.selected = language.code === meta.config.defaultLang; }); -}; -settingsController.user = async (req, res) => { - const [notificationTypes, groupData] = await Promise.all([ - notifications.getAllNotificationTypes(), - groups.getNonPrivilegeGroups('groups:createtime', 0, -1), - ]); - const notificationSettings = notificationTypes.map(type => ({ - name: type, - label: `[[notifications:${type.replace(/_/g, '-')}]]`, - })); - res.render('admin/settings/user', { - title: '[[admin/menu:settings/user]]', - notificationSettings: notificationSettings, - groupsExemptFromNewUserRestrictions: groupData, - }); -}; - -settingsController.post = async (req, res) => { - const groupData = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1); - res.render('admin/settings/post', { - title: '[[admin/menu:settings/post]]', - groupsExemptFromPostQueue: groupData, - }); -}; - -settingsController.advanced = async (req, res) => { - const groupData = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1); - res.render('admin/settings/advanced', { - title: '[[admin/menu:settings/advanced]]', - groupsExemptFromMaintenanceMode: groupData, + res.render('admin/settings/general', { + title: `[[admin/menu:settings/general]]`, + routes, + postSharing, + languages: languageData, + autoDetectLang: meta.config.autoDetectLang, }); }; @@ -107,6 +63,83 @@ settingsController.navigation = async function (req, res) { res.render('admin/settings/navigation', admin); }; +settingsController.user = async (req, res) => { + const [notificationTypes, groupData] = await Promise.all([ + notifications.getAllNotificationTypes(), + groups.getNonPrivilegeGroups('groups:createtime', 0, -1), + ]); + const notificationSettings = notificationTypes.map(type => ({ + name: type, + label: `[[notifications:${type.replace(/_/g, '-')}]]`, + })); + res.render('admin/settings/user', { + title: '[[admin/menu:settings/user]]', + notificationSettings: notificationSettings, + groupsExemptFromNewUserRestrictions: groupData, + }); +}; + +settingsController.reputation = async (req, res) => { + res.render(`admin/settings/reputation`, { + title: `[[admin/menu:settings/reputation]]`, + }); +}; + +settingsController.group = async (req, res) => { + res.render(`admin/settings/group`, { + title: `[[admin/menu:settings/group]]`, + }); +}; + +settingsController.tags = async (req, res) => { + res.render(`admin/settings/tags`, { + title: `[[admin/menu:settings/tags]]`, + }); +}; + +settingsController.post = async (req, res) => { + const groupData = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1); + res.render('admin/settings/post', { + title: '[[admin/menu:settings/post]]', + groupsExemptFromPostQueue: groupData, + }); +}; + +settingsController.uploads = async (req, res) => { + res.render(`admin/settings/uploads`, { + title: `[[admin/menu:settings/uploads]]`, + }); +}; + +settingsController.email = async (req, res) => { + const emails = await emailer.getTemplates(meta.config); + + res.render('admin/settings/email', { + title: '[[admin/menu:settings/email]]', + emails: emails, + sendable: emails.filter(e => !e.path.includes('_plaintext') && !e.path.includes('partials')).map(tpl => tpl.path), + services: emailer.listServices(), + }); +}; + +settingsController.chat = async (req, res) => { + res.render(`admin/settings/chat`, { + title: `[[admin/menu:settings/chat]]`, + }); +}; + +settingsController.pagination = async (req, res) => { + res.render(`admin/settings/pagination`, { + title: `[[admin/menu:settings/pagination]]`, + }); +}; + +settingsController.notifications = async (req, res) => { + res.render(`admin/settings/notifications`, { + title: `[[admin/menu:settings/notifications]]`, + }); +}; + settingsController.api = async (req, res) => { const page = parseInt(req.query.page, 10) || 1; const resultsPerPage = 50; @@ -123,3 +156,27 @@ settingsController.api = async (req, res) => { pagination: pagination.create(page, pageCount, req.query), }); }; + +settingsController.cookies = async (req, res) => { + res.render(`admin/settings/cookies`, { + title: `[[admin/menu:settings/cookies]]`, + }); +}; + +settingsController.webCrawler = async (req, res) => { + res.render(`admin/settings/web-crawler`, { + title: `[[admin/menu:settings/web-crawler]]`, + }); +}; + +settingsController.advanced = async (req, res) => { + const groupData = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1); + res.render('admin/settings/advanced', { + title: '[[admin/menu:settings/advanced]]', + groupsExemptFromMaintenanceMode: groupData, + }); +}; + + + + diff --git a/src/routes/admin.js b/src/routes/admin.js index 9e780d9104..f7f2c07884 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -32,15 +32,27 @@ module.exports = function (app, name, middleware, controllers) { helpers.setupAdminPageRoute(app, `/${name}/manage/uploads`, middlewares, controllers.admin.uploads.get); helpers.setupAdminPageRoute(app, `/${name}/manage/digest`, middlewares, controllers.admin.digest.get); - helpers.setupAdminPageRoute(app, `/${name}/settings/email`, middlewares, controllers.admin.settings.email); - helpers.setupAdminPageRoute(app, `/${name}/settings/user`, middlewares, controllers.admin.settings.user); - helpers.setupAdminPageRoute(app, `/${name}/settings/post`, middlewares, controllers.admin.settings.post); - helpers.setupAdminPageRoute(app, `/${name}/settings/advanced`, middlewares, controllers.admin.settings.advanced); + helpers.setupAdminPageRoute(app, `/${name}/settings/general`, middlewares, controllers.admin.settings.general); helpers.setupAdminPageRoute(app, `/${name}/settings/navigation`, middlewares, controllers.admin.settings.navigation); + helpers.setupAdminPageRoute(app, `/${name}/settings/user`, middlewares, controllers.admin.settings.user); + helpers.setupAdminPageRoute(app, `/${name}/settings/reputation`, middlewares, controllers.admin.settings.reputation); + helpers.setupAdminPageRoute(app, `/${name}/settings/group`, middlewares, controllers.admin.settings.group); + helpers.setupAdminPageRoute(app, `/${name}/settings/tags`, middlewares, controllers.admin.settings.tags); + helpers.setupAdminPageRoute(app, `/${name}/settings/post`, middlewares, controllers.admin.settings.post); + helpers.setupAdminPageRoute(app, `/${name}/settings/uploads`, middlewares, controllers.admin.settings.uploads); + helpers.setupAdminPageRoute(app, `/${name}/settings/email`, middlewares, controllers.admin.settings.email); + helpers.setupAdminPageRoute(app, `/${name}/settings/chat`, middlewares, controllers.admin.settings.chat); + helpers.setupAdminPageRoute(app, `/${name}/settings/pagination`, middlewares, controllers.admin.settings.pagination); + helpers.setupAdminPageRoute(app, `/${name}/settings/notifications`, middlewares, controllers.admin.settings.notifications); helpers.setupAdminPageRoute(app, `/${name}/settings/api`, middlewares, controllers.admin.settings.api); - helpers.setupAdminPageRoute(app, `/${name}/settings/:term?`, middlewares, controllers.admin.settings.get); + helpers.setupAdminPageRoute(app, `/${name}/settings/cookies`, middlewares, controllers.admin.settings.cookies); + helpers.setupAdminPageRoute(app, `/${name}/settings/web-crawler`, middlewares, controllers.admin.settings.webCrawler); + helpers.setupAdminPageRoute(app, `/${name}/settings/advanced`, middlewares, controllers.admin.settings.advanced); + + helpers.setupAdminPageRoute(app, `/${name}/appearance/themes`, middlewares, controllers.admin.appearance.themes); + helpers.setupAdminPageRoute(app, `/${name}/appearance/skins`, middlewares, controllers.admin.appearance.skins); + helpers.setupAdminPageRoute(app, `/${name}/appearance/customise`, middlewares, controllers.admin.appearance.customise); - helpers.setupAdminPageRoute(app, `/${name}/appearance/:term?`, middlewares, controllers.admin.appearance.get); helpers.setupAdminPageRoute(app, `/${name}/extend/plugins`, middlewares, controllers.admin.plugins.get); helpers.setupAdminPageRoute(app, `/${name}/extend/widgets`, middlewares, controllers.admin.extend.widgets.get); From b05dc7f7bd8e98024f8df7ace1fa933cdf192dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 19:16:09 -0500 Subject: [PATCH 25/35] test: fix test --- test/controllers-admin.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/controllers-admin.js b/test/controllers-admin.js index 7760bf128e..e428efe390 100644 --- a/test/controllers-admin.js +++ b/test/controllers-admin.js @@ -138,7 +138,7 @@ describe('Admin Controllers', () => { }); it('should load general settings page', async () => { - const { response, body } = await request.get(`${nconf.get('url')}/admin/settings`, { jar: jar }); + const { response, body } = await request.get(`${nconf.get('url')}/admin/settings/general`, { jar: jar }); assert.equal(response.statusCode, 200); assert(body); }); @@ -476,6 +476,12 @@ describe('Admin Controllers', () => { assert(body); }); + it('should load /admin/appearance/skins', async () => { + const { response, body } = await request.get(`${nconf.get('url')}/api/admin/appearance/skins`, { jar }); + assert.equal(response.statusCode, 200); + assert(body); + }); + it('should load /admin/appearance/customise', async () => { const { response, body } = await request.get(`${nconf.get('url')}/api/admin/appearance/customise`, { jar }); assert.equal(response.statusCode, 200); From 468d930a8dc4282f4ab5498c069d14c1af9ba596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 19:22:37 -0500 Subject: [PATCH 26/35] test: remove routes that no longer exist --- test/controllers-admin.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/test/controllers-admin.js b/test/controllers-admin.js index e428efe390..1d8a19c1bf 100644 --- a/test/controllers-admin.js +++ b/test/controllers-admin.js @@ -423,23 +423,6 @@ describe('Admin Controllers', () => { assert(body); }); - it('should load /admin/settings/languages', async () => { - const { response, body } = await request.get(`${nconf.get('url')}/api/admin/settings/languages`, { jar }); - assert.equal(response.statusCode, 200); - assert(body); - }); - - it('should load /admin/settings/social', async () => { - const { body } = await request.get(`${nconf.get('url')}/api/admin/settings/general`, { jar }); - assert(body); - const sharing = body.postSharing.map(network => network && network.id); - assert(sharing.includes('facebook')); - assert(sharing.includes('twitter')); - assert(sharing.includes('linkedin')); - assert(sharing.includes('whatsapp')); - assert(sharing.includes('telegram')); - }); - it('should load /admin/manage/tags', async () => { const { response, body } = await request.get(`${nconf.get('url')}/api/admin/manage/tags`, { jar }); assert.equal(response.statusCode, 200); From 6eb2807747057269569422ae5f6526007c4e37a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 19:38:40 -0500 Subject: [PATCH 27/35] test: add missing spec files --- public/openapi/read.yaml | 38 +++++++++++++++---- .../appearance/{term.yaml => customise.yaml} | 7 ---- .../openapi/read/admin/appearance/skins.yaml | 11 ++++++ .../openapi/read/admin/appearance/themes.yaml | 11 ++++++ public/openapi/read/admin/settings/chat.yaml | 16 ++++++++ .../openapi/read/admin/settings/cookies.yaml | 16 ++++++++ .../settings/{term.yaml => general.yaml} | 7 ---- public/openapi/read/admin/settings/group.yaml | 16 ++++++++ .../read/admin/settings/notifications.yaml | 16 ++++++++ .../read/admin/settings/pagination.yaml | 16 ++++++++ .../read/admin/settings/reputation.yaml | 16 ++++++++ public/openapi/read/admin/settings/tags.yaml | 16 ++++++++ .../openapi/read/admin/settings/uploads.yaml | 16 ++++++++ .../read/admin/settings/web-crawler.yaml | 16 ++++++++ 14 files changed, 196 insertions(+), 22 deletions(-) rename public/openapi/read/admin/appearance/{term.yaml => customise.yaml} (65%) create mode 100644 public/openapi/read/admin/appearance/skins.yaml create mode 100644 public/openapi/read/admin/appearance/themes.yaml create mode 100644 public/openapi/read/admin/settings/chat.yaml create mode 100644 public/openapi/read/admin/settings/cookies.yaml rename public/openapi/read/admin/settings/{term.yaml => general.yaml} (87%) create mode 100644 public/openapi/read/admin/settings/group.yaml create mode 100644 public/openapi/read/admin/settings/notifications.yaml create mode 100644 public/openapi/read/admin/settings/pagination.yaml create mode 100644 public/openapi/read/admin/settings/reputation.yaml create mode 100644 public/openapi/read/admin/settings/tags.yaml create mode 100644 public/openapi/read/admin/settings/uploads.yaml create mode 100644 public/openapi/read/admin/settings/web-crawler.yaml diff --git a/public/openapi/read.yaml b/public/openapi/read.yaml index f6104b495e..7df263b819 100644 --- a/public/openapi/read.yaml +++ b/public/openapi/read.yaml @@ -80,18 +80,36 @@ paths: $ref: 'read/admin/dashboard/topics.yaml' /api/admin/dashboard/searches: $ref: 'read/admin/dashboard/searches.yaml' - "/api/admin/settings/{term}": - $ref: 'read/admin/settings/term.yaml' + "/api/admin/settings/general": + $ref: 'read/admin/settings/general.yaml' /api/admin/settings/navigation: $ref: 'read/admin/settings/navigation.yaml' - /api/admin/settings/api: - $ref: 'read/admin/settings/api.yaml' - /api/admin/settings/email: - $ref: 'read/admin/settings/email.yaml' /api/admin/settings/user: $ref: 'read/admin/settings/user.yaml' + /api/admin/settings/reputation: + $ref: 'read/admin/settings/reputation.yaml' + /api/admin/settings/group: + $ref: 'read/admin/settings/group.yaml' + /api/admin/settings/tags: + $ref: 'read/admin/settings/tags.yaml' /api/admin/settings/post: $ref: 'read/admin/settings/post.yaml' + /api/admin/settings/uploads: + $ref: 'read/admin/settings/uploads.yaml' + /api/admin/settings/email: + $ref: 'read/admin/settings/email.yaml' + /api/admin/settings/chat: + $ref: 'read/admin/settings/chat.yaml' + /api/admin/settings/pagination: + $ref: 'read/admin/settings/pagination.yaml' + /api/admin/settings/notifications: + $ref: 'read/admin/settings/notifications.yaml' + /api/admin/settings/api: + $ref: 'read/admin/settings/api.yaml' + /api/admin/settings/cookies: + $ref: 'read/admin/settings/cookies.yaml' + /api/admin/settings/web-crawler: + $ref: 'read/admin/settings/web-crawler.yaml' /api/admin/settings/advanced: $ref: 'read/admin/settings/advanced.yaml' /api/admin/manage/categories: @@ -120,8 +138,12 @@ paths: $ref: 'read/admin/manage/uploads.yaml' /api/admin/manage/digest: $ref: 'read/admin/manage/digest.yaml' - "/api/admin/appearance/{term}": - $ref: 'read/admin/appearance/term.yaml' + "/api/admin/appearance/themes": + $ref: 'read/admin/appearance/themes.yaml' + "/api/admin/appearance/skins": + $ref: 'read/admin/appearance/skins.yaml' + "/api/admin/appearance/customise": + $ref: 'read/admin/appearance/customise.yaml' /api/admin/extend/plugins: $ref: 'read/admin/extend/plugins.yaml' /api/admin/extend/widgets: diff --git a/public/openapi/read/admin/appearance/term.yaml b/public/openapi/read/admin/appearance/customise.yaml similarity index 65% rename from public/openapi/read/admin/appearance/term.yaml rename to public/openapi/read/admin/appearance/customise.yaml index 5c8364fa31..d2b2eabb68 100644 --- a/public/openapi/read/admin/appearance/term.yaml +++ b/public/openapi/read/admin/appearance/customise.yaml @@ -2,13 +2,6 @@ get: tags: - admin summary: Get appearance settings - parameters: - - name: term - in: path - required: true - schema: - type: string - example: themes responses: "200": description: "" diff --git a/public/openapi/read/admin/appearance/skins.yaml b/public/openapi/read/admin/appearance/skins.yaml new file mode 100644 index 0000000000..d2b2eabb68 --- /dev/null +++ b/public/openapi/read/admin/appearance/skins.yaml @@ -0,0 +1,11 @@ +get: + tags: + - admin + summary: Get appearance settings + responses: + "200": + description: "" + content: + application/json: + schema: + $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/appearance/themes.yaml b/public/openapi/read/admin/appearance/themes.yaml new file mode 100644 index 0000000000..d2b2eabb68 --- /dev/null +++ b/public/openapi/read/admin/appearance/themes.yaml @@ -0,0 +1,11 @@ +get: + tags: + - admin + summary: Get appearance settings + responses: + "200": + description: "" + content: + application/json: + schema: + $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/chat.yaml b/public/openapi/read/admin/settings/chat.yaml new file mode 100644 index 0000000000..402f9b173c --- /dev/null +++ b/public/openapi/read/admin/settings/chat.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get chat settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/cookies.yaml b/public/openapi/read/admin/settings/cookies.yaml new file mode 100644 index 0000000000..8f454839e5 --- /dev/null +++ b/public/openapi/read/admin/settings/cookies.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get cookie settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/term.yaml b/public/openapi/read/admin/settings/general.yaml similarity index 87% rename from public/openapi/read/admin/settings/term.yaml rename to public/openapi/read/admin/settings/general.yaml index 86eaf50b4e..d19ff555ee 100644 --- a/public/openapi/read/admin/settings/term.yaml +++ b/public/openapi/read/admin/settings/general.yaml @@ -2,13 +2,6 @@ get: tags: - admin summary: Get system settings - parameters: - - name: term - in: path - required: true - schema: - type: string - example: general responses: "200": description: "" diff --git a/public/openapi/read/admin/settings/group.yaml b/public/openapi/read/admin/settings/group.yaml new file mode 100644 index 0000000000..e4b0157a2f --- /dev/null +++ b/public/openapi/read/admin/settings/group.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get group settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/notifications.yaml b/public/openapi/read/admin/settings/notifications.yaml new file mode 100644 index 0000000000..3ef8e368ab --- /dev/null +++ b/public/openapi/read/admin/settings/notifications.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get notification settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/pagination.yaml b/public/openapi/read/admin/settings/pagination.yaml new file mode 100644 index 0000000000..cb598ef643 --- /dev/null +++ b/public/openapi/read/admin/settings/pagination.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get pagination settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/reputation.yaml b/public/openapi/read/admin/settings/reputation.yaml new file mode 100644 index 0000000000..91f6ea0561 --- /dev/null +++ b/public/openapi/read/admin/settings/reputation.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get reputation settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/tags.yaml b/public/openapi/read/admin/settings/tags.yaml new file mode 100644 index 0000000000..53d82a4355 --- /dev/null +++ b/public/openapi/read/admin/settings/tags.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get tag settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/uploads.yaml b/public/openapi/read/admin/settings/uploads.yaml new file mode 100644 index 0000000000..f181df0792 --- /dev/null +++ b/public/openapi/read/admin/settings/uploads.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get upload settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/read/admin/settings/web-crawler.yaml b/public/openapi/read/admin/settings/web-crawler.yaml new file mode 100644 index 0000000000..57963c5901 --- /dev/null +++ b/public/openapi/read/admin/settings/web-crawler.yaml @@ -0,0 +1,16 @@ +get: + tags: + - admin + summary: Get web crawler settings + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file From 2a085cdba80c9fb28f39568d078f3a09f81e0dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 9 Dec 2024 21:27:32 -0500 Subject: [PATCH 28/35] chore: up persona --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 69e40d598d..17a870f895 100644 --- a/install/package.json +++ b/install/package.json @@ -110,7 +110,7 @@ "nodebb-theme-harmony": "1.2.88", "nodebb-theme-lavender": "7.1.16", "nodebb-theme-peace": "2.2.28", - "nodebb-theme-persona": "13.3.57", + "nodebb-theme-persona": "13.3.58", "nodebb-widget-essentials": "7.0.31", "nodemailer": "6.9.16", "nprogress": "0.2.0", From 521e679cf158f76ef481c0c6b5bec97e1cba10f2 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 10 Dec 2024 09:18:56 +0000 Subject: [PATCH 29/35] Latest translations and fallbacks --- public/language/zh-CN/aria.json | 2 +- public/language/zh-CN/modules.json | 4 ++-- public/language/zh-CN/topic.json | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/public/language/zh-CN/aria.json b/public/language/zh-CN/aria.json index c69f1844a9..5bfde2aa6a 100644 --- a/public/language/zh-CN/aria.json +++ b/public/language/zh-CN/aria.json @@ -1,5 +1,5 @@ { - "post-sort-option": "帖子分类选项,1%", + "post-sort-option": "帖子分类选项,%1", "topic-sort-option": "主题分类选项,%1", "user-avatar-for": "用户头像%1", "user-watched-tags": "用户关注标签", diff --git a/public/language/zh-CN/modules.json b/public/language/zh-CN/modules.json index a20595f84f..f7e63925ff 100644 --- a/public/language/zh-CN/modules.json +++ b/public/language/zh-CN/modules.json @@ -38,8 +38,8 @@ "chat.no-pinned-messages": "这里没有已置顶消息", "chat.pin-message": "置顶消息", "chat.unpin-message": "取消置顶消息", - "chat.public-rooms": "公开房间(1%)", - "chat.private-rooms": "私有房间(1%)", + "chat.public-rooms": "公开房间(%1)", + "chat.private-rooms": "私有房间(%1)", "chat.create-room": "创建聊天室", "chat.private.option": "私有(仅已加入房间用户可见)", "chat.public.option": "公开(对选中组里的所有用户可见)", diff --git a/public/language/zh-CN/topic.json b/public/language/zh-CN/topic.json index 33e2575729..515fe112dc 100644 --- a/public/language/zh-CN/topic.json +++ b/public/language/zh-CN/topic.json @@ -117,9 +117,9 @@ "thread-tools.purge-confirm": "确认清除此主题吗?", "thread-tools.merge-topics": "合并主题", "thread-tools.merge": "合并主题", - "topic-move-success": "注意:此主题将会被移动到“1%”。点击此处可取消。", + "topic-move-success": "注意:此主题将会被移动到“%1”。点击此处可取消。", "topic-move-multiple-success": "注意:以下主题将会被移动到“%1”,点击此处可取消。", - "topic-move-all-success": "注意 :全部主题都将被移动到“1%”,点击此处可取消。", + "topic-move-all-success": "注意 :全部主题都将被移动到“%1”,点击此处可取消。", "topic-move-undone": "撤销主题移动", "topic-move-posts-success": "此帖子将马上移动。点击此处撤销", "topic-move-posts-undone": "撤销帖子移动", @@ -170,7 +170,7 @@ "composer.schedule": "定时", "composer.replying-to": "正在回复 %1", "composer.new-topic": "新主题", - "composer.editing-in": "在 1% 中编辑帖子", + "composer.editing-in": "在 %1 中编辑帖子", "composer.uploading": "正在上传...", "composer.thumb-url-label": "粘贴主题缩略图网址", "composer.thumb-title": "给此主题添加缩略图", From 04eb9e1ad7332e21aea9cf7ed2e163f02928abf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 10 Dec 2024 09:47:26 -0500 Subject: [PATCH 30/35] fix: closes #12963, change translation to general --- src/views/admin/settings/email.tpl | 2 +- src/views/admin/settings/general.tpl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/admin/settings/email.tpl b/src/views/admin/settings/email.tpl index 549b23a234..a89fb850a8 100644 --- a/src/views/admin/settings/email.tpl +++ b/src/views/admin/settings/email.tpl @@ -103,7 +103,7 @@
[[admin/settings/email:smtp-transport]]
-
+
[[admin/settings/email:smtp-transport-help]]
diff --git a/src/views/admin/settings/general.tpl b/src/views/admin/settings/general.tpl index c2c6f27caa..7070fbf0ee 100644 --- a/src/views/admin/settings/general.tpl +++ b/src/views/admin/settings/general.tpl @@ -293,7 +293,7 @@
-
[[admin/settings/social:post-sharing]]
+
[[admin/settings/general:post-sharing]]
{{{ each postSharing }}} @@ -304,7 +304,7 @@
{{{ end }}} -

[[admin/settings/social:info-plugins-additional]]

+

[[admin/settings/general:info-plugins-additional]]

From 8f465afc97282dbc6bb266ae91565ac97b153c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 10 Dec 2024 10:17:38 -0500 Subject: [PATCH 31/35] refactor: add csrf protection to webinstall POST route --- install/web.js | 18 +++++++++++++++--- src/views/install/index.tpl | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/install/web.js b/install/web.js index 92fe675c22..cd38c3be6e 100644 --- a/install/web.js +++ b/install/web.js @@ -2,6 +2,7 @@ const winston = require('winston'); const express = require('express'); +const session = require('express-session'); const bodyParser = require('body-parser'); const fs = require('fs'); const path = require('path'); @@ -13,7 +14,10 @@ const nconf = require('nconf'); const Benchpress = require('benchpressjs'); const { mkdirp } = require('mkdirp'); const { paths } = require('../src/constants'); -const sass = require('../src/utils').getSass(); +const utils = require('../src/utils'); + +const sass = utils.getSass(); +const { generateToken, csrfSynchronisedProtection } = require('../src/middleware/csrf'); const app = express(); let server; @@ -73,6 +77,13 @@ web.install = async function (port) { app.use(bodyParser.urlencoded({ extended: true, })); + + app.use(session({ + secret: utils.generateUUID(), + resave: false, + saveUninitialized: false, + })); + try { await Promise.all([ compileTemplate(), @@ -103,8 +114,8 @@ function launchExpress(port) { } function setupRoutes() { - app.get('/', welcome); - app.post('/', install); + app.get('/', csrfSynchronisedProtection, welcome); + app.post('/', csrfSynchronisedProtection, install); app.get('/testdb', testDatabase); app.get('/ping', ping); app.get('/sping', ping); @@ -160,6 +171,7 @@ function welcome(req, res) { minimumPasswordStrength: defaults.minimumPasswordStrength, installing: installing, percentInstalled: installing ? ((Date.now() - timeStart) / totalTime * 100).toFixed(2) : 0, + csrf_token: generateToken(req), }); } diff --git a/src/views/install/index.tpl b/src/views/install/index.tpl index f41400f734..aa703f8356 100644 --- a/src/views/install/index.tpl +++ b/src/views/install/index.tpl @@ -35,6 +35,8 @@ You are just a few steps away from launching your own NodeBB forum!

+ + {{{ if !skipGeneralSetup }}}

From 38520769a3c85f9745ee3cfaa270f932d7d1edca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 10 Dec 2024 10:21:06 -0500 Subject: [PATCH 32/35] refactor: check if caches have the requested cache name --- src/controllers/admin/cache.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/admin/cache.js b/src/controllers/admin/cache.js index 2faad03fc2..f46d7fd41e 100644 --- a/src/controllers/admin/cache.js +++ b/src/controllers/admin/cache.js @@ -52,7 +52,7 @@ cacheController.dump = async function (req, res, next) { local: require('../../cache'), }; caches = await plugins.hooks.fire('filter:admin.cache.get', caches); - if (!caches[req.query.name]) { + if (!caches.hasOwnProperty(req.query.name)) { return next(); } From 3b713afed3cbefab318cbe48ad3a46a620dc4a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 10 Dec 2024 10:37:48 -0500 Subject: [PATCH 33/35] fix: make sure theme screenshot starts with themeDir --- src/controllers/admin/themes.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/controllers/admin/themes.js b/src/controllers/admin/themes.js index db08d08f84..339884c95d 100644 --- a/src/controllers/admin/themes.js +++ b/src/controllers/admin/themes.js @@ -20,12 +20,18 @@ themesController.get = async function (req, res, next) { themeConfig = JSON.parse(themeConfig); } catch (err) { if (err.code === 'ENOENT') { - return next(Error('invalid-data')); + return next(Error('[[error:invalid-data]]')); } return next(err); } - const screenshotPath = themeConfig.screenshot ? path.join(themeDir, themeConfig.screenshot) : defaultScreenshotPath; - const exists = await file.exists(screenshotPath); + const screenshotPath = themeConfig.screenshot ? + path.join(themeDir, themeConfig.screenshot) : + ''; + + if (screenshotPath && !screenshotPath.startsWith(themeDir)) { + throw new Error('[[error:invalid-path]]'); + } + const exists = screenshotPath ? await file.exists(screenshotPath) : false; res.sendFile(exists ? screenshotPath : defaultScreenshotPath); }; From e0c345b2b850f4c0f45f650abd00637472f84bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 10 Dec 2024 13:39:31 -0500 Subject: [PATCH 34/35] chore: up themes --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 17a870f895..f5a7c06027 100644 --- a/install/package.json +++ b/install/package.json @@ -108,9 +108,9 @@ "nodebb-plugin-spam-be-gone": "2.3.0", "nodebb-rewards-essentials": "1.0.0", "nodebb-theme-harmony": "1.2.88", - "nodebb-theme-lavender": "7.1.16", + "nodebb-theme-lavender": "7.1.17", "nodebb-theme-peace": "2.2.28", - "nodebb-theme-persona": "13.3.58", + "nodebb-theme-persona": "13.3.59", "nodebb-widget-essentials": "7.0.31", "nodemailer": "6.9.16", "nprogress": "0.2.0", From 607d1895ce57518925aaebcc9e52b45b4d2aff10 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:41:58 -0500 Subject: [PATCH 35/35] chore(deps): update dependency lint-staged to v15.2.11 (#12964) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f5a7c06027..1a8c912167 100644 --- a/install/package.json +++ b/install/package.json @@ -167,7 +167,7 @@ "grunt-contrib-watch": "1.1.0", "husky": "8.0.3", "jsdom": "25.0.1", - "lint-staged": "15.2.10", + "lint-staged": "15.2.11", "mocha": "11.0.1", "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5",