mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-30 20:30:32 +01:00
Merge branch 'master' into develop
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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!",
|
||||
|
||||
@@ -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
|
||||
@@ -23,7 +23,7 @@ put:
|
||||
example: '123456'
|
||||
newPassword:
|
||||
type: string
|
||||
example: '123456'
|
||||
example: '654321'
|
||||
required:
|
||||
- newPassword
|
||||
responses:
|
||||
|
||||
@@ -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.loggedIn) {
|
||||
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;
|
||||
|
||||
@@ -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]]');
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
{{{ if alreadyValidated }}}
|
||||
<div class="alert alert-info">
|
||||
<p>[[notifications:email-confirm-error-message-already-validated]]</p>
|
||||
{{{ end }}}
|
||||
|
||||
{{{ if error }}}
|
||||
<div class="alert alert-warning">
|
||||
<p>[[notifications:email-confirm-error-message]]</p>
|
||||
{{{ end }}}
|
||||
|
||||
{{{ if (!error && !alreadyValidated )}}}
|
||||
<div class="alert alert-success">
|
||||
<strong>[[notifications:email-confirmed]]</strong>
|
||||
<p>[[notifications:email-confirmed-message]]</p>
|
||||
<p>
|
||||
{{{ end }}}
|
||||
<p class="mb-0">
|
||||
<a href="{config.relative_path}/">[[notifications:back-to-home, {config.siteTitle}]]</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,40 +1,42 @@
|
||||
<div class="row col-12 col-sm-6 offset-sm-3">
|
||||
{{{ if valid }}}
|
||||
<div class="card card-body bg-light">
|
||||
{{{ if displayExpiryNotice }}}
|
||||
<div class="alert alert-warning">
|
||||
[[reset_password:password-expired]]
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 offset-sm-3">
|
||||
{{{ if valid }}}
|
||||
<div class="card card-body bg-light">
|
||||
{{{ if displayExpiryNotice }}}
|
||||
<div class="alert alert-warning">
|
||||
[[reset_password:password-expired]]
|
||||
</div>
|
||||
{{{ end }}}
|
||||
<div class="alert alert-success alert-dismissible hidden" id="success">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
<strong>[[reset_password:password-changed.title]]</strong>
|
||||
<p>[[reset_password:password-changed.message]]</p>
|
||||
</div>
|
||||
<div class="alert alert-warning hidden" id="notice">
|
||||
<strong></strong>
|
||||
<p></p>
|
||||
</div>
|
||||
<form onsubmit="return false;" id="reset-form">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="password">[[reset_password:new-password]]</label>
|
||||
<input class="form-control" type="password" placeholder="[[reset_password:new-password]]" id="password" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="repeat">[[reset_password:repeat-password]]</label>
|
||||
<input class="form-control" type="password" placeholder="[[reset_password:repeat-password]]" id="repeat" />
|
||||
</div>
|
||||
<button class="btn btn-primary" id="reset" type="submit">[[reset_password:reset-password]]</button>
|
||||
</form>
|
||||
</div>
|
||||
{{{ else }}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">[[reset_password:wrong-reset-code.title]]</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>[[reset_password:wrong-reset-code.message]]</p>
|
||||
</div>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
<div class="alert alert-success alert-dismissible hidden" id="success">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
<strong>[[reset_password:password-changed.title]]</strong>
|
||||
<p>[[reset_password:password-changed.message]]</p>
|
||||
</div>
|
||||
<div class="alert alert-warning hidden" id="notice">
|
||||
<strong></strong>
|
||||
<p></p>
|
||||
</div>
|
||||
<form onsubmit="return false;" id="reset-form">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="password">[[reset_password:new-password]]</label>
|
||||
<input class="form-control" type="password" placeholder="[[reset_password:new-password]]" id="password" /><br />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="repeat">[[reset_password:repeat-password]]</label>
|
||||
<input class="form-control" type="password" placeholder="[[reset_password:repeat-password]]" id="repeat" /><br />
|
||||
</div>
|
||||
<button class="btn btn-primary btn-block" id="reset" type="submit">[[reset_password:reset-password]]</button>
|
||||
</form>
|
||||
</div>
|
||||
{{{ else }}}
|
||||
<div class="card text-bg-danger">
|
||||
<h5 class="card-header">
|
||||
[[reset_password:wrong-reset-code.title]]
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<p>[[reset_password:wrong-reset-code.message]]</p>
|
||||
</div>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
11
test/api.js
11
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;
|
||||
|
||||
|
||||
12
test/user.js
12
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' });
|
||||
|
||||
Reference in New Issue
Block a user