From f361df0193eddf93b1840e9ff195534974b2520f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 23 Aug 2024 09:52:00 -0400 Subject: [PATCH 1/6] fix: #12754, throw if currentPwd == newPwd --- public/language/en-GB/user.json | 1 + src/user/profile.js | 3 +++ test/user.js | 12 ++++++++++++ 3 files changed, 16 insertions(+) diff --git a/public/language/en-GB/user.json b/public/language/en-GB/user.json index b010898322..73bce4498a 100644 --- a/public/language/en-GB/user.json +++ b/public/language/en-GB/user.json @@ -81,6 +81,7 @@ "change-password": "Change Password", "change-password-error": "Invalid Password!", "change-password-error-wrong-current": "Your current password is not correct!", + "change-password-error-same-password": "Your new password matches your current password, please use a new password.", "change-password-error-match": "Passwords must match!", "change-password-error-privileges": "You do not have the rights to change this password.", "change-password-success": "Your password is updated!", diff --git a/src/user/profile.js b/src/user/profile.js index 9d65037bbe..e9c751e40f 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -317,6 +317,9 @@ module.exports = function (User) { if (!correct) { throw new Error('[[user:change-password-error-wrong-current]]'); } + if (data.currentPassword === data.newPassword) { + throw new Error('[[user:change-password-error-same-password]]'); + } } const hashedPassword = await User.hashPassword(data.newPassword); diff --git a/test/user.js b/test/user.js index 25c0ddc6f0..9b7fc88f18 100644 --- a/test/user.js +++ b/test/user.js @@ -776,6 +776,18 @@ describe('User', () => { assert(correct); }); + it('should not let user change their password to their current password', async () => { + const uid = await User.create({ username: 'changepasswordsame', password: '123456' }); + await assert.rejects( + apiUser.changePassword({ uid: uid }, { + uid: uid, + newPassword: '123456', + currentPassword: '123456', + }), + { message: '[[user:change-password-error-same-password]]' }, + ); + }); + it('should not let user change another user\'s password', async () => { const regularUserUid = await User.create({ username: 'regularuserpwdchange', password: 'regularuser1234' }); const uid = await User.create({ username: 'changeadminpwd1', password: '123456' }); From be32cf4404f5f71c3e2d01d9f57dc5d7d29c4d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 23 Aug 2024 10:38:31 -0400 Subject: [PATCH 2/6] test: since admin pwd changes in test, login with new pwd --- public/openapi/write/users/uid/password.yaml | 2 +- test/api.js | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/public/openapi/write/users/uid/password.yaml b/public/openapi/write/users/uid/password.yaml index 1a52f85e53..7d1dc2e938 100644 --- a/public/openapi/write/users/uid/password.yaml +++ b/public/openapi/write/users/uid/password.yaml @@ -23,7 +23,7 @@ put: example: '123456' newPassword: type: string - example: '123456' + example: '654321' required: - newPassword responses: diff --git a/test/api.js b/test/api.js index 0ea9918953..d8ad5e4ca4 100644 --- a/test/api.js +++ b/test/api.js @@ -562,8 +562,15 @@ describe('API', async () => { const reloginPaths = ['GET /api/user/{userslug}/edit/email', 'PUT /users/{uid}/password', 'DELETE /users/{uid}/sessions/{uuid}']; if (reloginPaths.includes(`${method.toUpperCase()} ${path}`)) { ({ jar } = await helpers.loginUser('admin', '123456')); - const sessionIds = await db.getSortedSetRange('uid:1:sessions', 0, -1); - const sessObj = await db.sessionStoreGet(sessionIds[0]); + let sessionIds = await db.getSortedSetRange('uid:1:sessions', 0, -1); + let sessObj = await db.sessionStoreGet(sessionIds[0]); + if (!sessObj) { + // password changed so login with new pwd + ({ jar } = await helpers.loginUser('admin', '654321')); + sessionIds = await db.getSortedSetRange('uid:1:sessions', 0, -1); + sessObj = await db.sessionStoreGet(sessionIds[0]); + } + const { uuid } = sessObj.meta; mocks.delete['/users/{uid}/sessions/{uuid}'][1].example = uuid; From 20053af6844829d8091751846963ebb961c684dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 26 Aug 2024 13:46:12 -0400 Subject: [PATCH 3/6] fix: reset form/invalid code style --- src/views/reset_code.tpl | 74 +++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/views/reset_code.tpl b/src/views/reset_code.tpl index 03e22692a8..94bbf9fe75 100644 --- a/src/views/reset_code.tpl +++ b/src/views/reset_code.tpl @@ -1,40 +1,42 @@ -
- {{{ if valid }}} -
- {{{ if displayExpiryNotice }}} -
- [[reset_password:password-expired]] +
+
+ {{{ if valid }}} +
+ {{{ if displayExpiryNotice }}} +
+ [[reset_password:password-expired]] +
+ {{{ end }}} + + +
+
+ + +
+
+ + +
+ +
+
+ {{{ else }}} +
+
+
[[reset_password:wrong-reset-code.title]]
+
+
+

[[reset_password:wrong-reset-code.message]]

+
{{{ end }}} - - -
-
- -
-
-
- -
-
- -
- {{{ else }}} -
-
- [[reset_password:wrong-reset-code.title]] -
-
-

[[reset_password:wrong-reset-code.message]]

-
-
- {{{ end }}}
\ No newline at end of file From 01a2f0e73076b2d5eb8de3ba6524fb88052bbe1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 26 Aug 2024 14:47:43 -0400 Subject: [PATCH 4/6] feat: show a friendly message on invalid or expired code, closes #12738 --- public/language/en-GB/notifications.json | 1 + src/controllers/index.js | 23 +++++++++++++++++------ src/views/confirm.tpl | 16 ++++++++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/public/language/en-GB/notifications.json b/public/language/en-GB/notifications.json index 2782fdaff9..ebfd7b1d7b 100644 --- a/public/language/en-GB/notifications.json +++ b/public/language/en-GB/notifications.json @@ -83,6 +83,7 @@ "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", + "email-confirm-error-message-already-validated": "Your email address was already validated.", "email-confirm-sent": "Confirmation email sent.", "none": "None", diff --git a/src/controllers/index.js b/src/controllers/index.js index 2cf50a7785..b3542851ee 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -219,20 +219,31 @@ Controllers.registerInterstitial = async function (req, res, next) { } }; -Controllers.confirmEmail = async (req, res, next) => { +Controllers.confirmEmail = async (req, res) => { + function renderPage(opts = {}) { + res.render('confirm', { + title: '[[pages:confirm]]', + ...opts, + }); + } try { + if (req.uid) { + const emailValidated = await user.getUserField(req.uid, 'email:confirmed'); + if (emailValidated) { + return renderPage({ alreadyValidated: true }); + } + } await user.email.confirmByCode(req.params.code, req.session.id); if (req.session.registration) { // After confirmation, no need to send user back to email change form delete req.session.registration.updateEmail; } - res.render('confirm', { - title: '[[pages:confirm]]', - }); + renderPage(); } catch (e) { - if (e.message === '[[error:invalid-data]]') { - return next(); + if (e.message === '[[error:invalid-data]]' || e.message === '[[error:confirm-email-expired]]') { + renderPage({ error: true }); + return; } throw e; diff --git a/src/views/confirm.tpl b/src/views/confirm.tpl index fb81b63823..0235ced0d5 100644 --- a/src/views/confirm.tpl +++ b/src/views/confirm.tpl @@ -1,7 +1,19 @@ +{{{ if alreadyValidated }}} +
+

[[notifications:email-confirm-error-message-already-validated]]

+{{{ end }}} + +{{{ if error }}} +
+

[[notifications:email-confirm-error-message]]

+{{{ end }}} + +{{{ if (!error && !alreadyValidated )}}}
[[notifications:email-confirmed]]

[[notifications:email-confirmed-message]]

-

+{{{ end }}} +

[[notifications:back-to-home, {config.siteTitle}]]

-
+
\ No newline at end of file From 5fa8ddbcf915e0251e4389aab3610418b6f7f399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 26 Aug 2024 14:52:30 -0400 Subject: [PATCH 5/6] test: fix spec --- public/openapi/read/confirm/code.yaml | 3 +++ src/controllers/index.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/public/openapi/read/confirm/code.yaml b/public/openapi/read/confirm/code.yaml index 9d55b016c1..9677cb1a66 100644 --- a/public/openapi/read/confirm/code.yaml +++ b/public/openapi/read/confirm/code.yaml @@ -24,6 +24,9 @@ get: error: type: string description: Translation key for client-side localisation + alreadyValidated: + type: boolean + description: set to true if the email was already validated required: - title - $ref: ../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/src/controllers/index.js b/src/controllers/index.js index b3542851ee..299050e37d 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -227,7 +227,7 @@ Controllers.confirmEmail = async (req, res) => { }); } try { - if (req.uid) { + if (req.loggedIn) { const emailValidated = await user.getUserField(req.uid, 'email:confirmed'); if (emailValidated) { return renderPage({ alreadyValidated: true }); From c0b30ea4efef88c154ac8b1dc9818325d71b076e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 27 Aug 2024 10:23:21 -0400 Subject: [PATCH 6/6] fix: closes #12758, show different error message for block --- public/language/en-GB/error.json | 1 + src/messaging/index.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index d849187bae..c8d52acb6e 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -179,6 +179,7 @@ "cant-chat-with-yourself": "You can't chat with yourself!", "chat-restricted": "This user has restricted their chat messages. They must follow you before you can chat with them", + "chat-user-blocked": "You have been blocked by this user.", "chat-disabled": "Chat system disabled", "too-many-messages": "You have sent too many messages, please wait awhile.", "invalid-chat-message": "Invalid chat message", diff --git a/src/messaging/index.js b/src/messaging/index.js index 7a2cd617a6..eda2bd4ac0 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -363,7 +363,10 @@ Messaging.canMessageUser = async (uid, toUid) => { user.blocks.is(uid, toUid), ]); - if (isBlocked || (settings.restrictChat && !isAdmin && !isModerator && !isFollowing)) { + if (isBlocked) { + throw new Error('[[error:chat-user-blocked]]'); + } + if (settings.restrictChat && !isAdmin && !isModerator && !isFollowing) { throw new Error('[[error:chat-restricted]]'); }