mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-04 21:15:55 +01:00
feat: present a password challenge on email update flow
This commit is contained in:
@@ -216,5 +216,6 @@
|
||||
"emailUpdate.intro": "Please enter your email address below. This forum uses your email address for scheduled digest and notifications, as well as for account recovery in the event of a lost password.",
|
||||
"emailUpdate.optional": "<strong>This field is optional</strong>. You are not obligated to provide your email address, but without a validated email you will not be able to recover your account or login with your email.",
|
||||
"emailUpdate.required": "<strong>This field is required</strong>.",
|
||||
"emailUpdate.change-instructions": "A confirmation email will be sent to the entered email address with a unique link. Accessing that link will confirm your ownership of the email address and it will become active on your account. At any time, you are able to update your email on file from within your account page."
|
||||
"emailUpdate.change-instructions": "A confirmation email will be sent to the entered email address with a unique link. Accessing that link will confirm your ownership of the email address and it will become active on your account. At any time, you are able to update your email on file from within your account page.",
|
||||
"emailUpdate.password-challenge": "Please enter your password in order to verify account ownership."
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const winston = require('winston');
|
||||
const util = require('util');
|
||||
|
||||
const user = require('.');
|
||||
const db = require('../database');
|
||||
@@ -9,6 +10,8 @@ const privileges = require('../privileges');
|
||||
const plugins = require('../plugins');
|
||||
const utils = require('../utils');
|
||||
|
||||
const sleep = util.promisify(setTimeout);
|
||||
|
||||
const Interstitials = module.exports;
|
||||
|
||||
Interstitials.email = async (data) => {
|
||||
@@ -19,6 +22,7 @@ Interstitials.email = async (data) => {
|
||||
return data;
|
||||
}
|
||||
|
||||
const isAdminOrGlobalMod = await user.isAdminOrGlobalMod(data.req.uid);
|
||||
let email;
|
||||
if (data.userData.uid) {
|
||||
email = await user.getUserField(data.userData.uid, 'email');
|
||||
@@ -29,12 +33,13 @@ Interstitials.email = async (data) => {
|
||||
data: {
|
||||
email,
|
||||
requireEmailAddress: meta.config.requireEmailAddress,
|
||||
update: !!data.userData.uid,
|
||||
},
|
||||
callback: async (userData, formData) => {
|
||||
// Validate and send email confirmation
|
||||
if (userData.uid) {
|
||||
const [isAdminOrGlobalMod, canEdit, current, { allowed, error }] = await Promise.all([
|
||||
user.isAdminOrGlobalMod(data.req.uid),
|
||||
const [isPasswordCorrect, canEdit, current, { allowed, error }] = await Promise.all([
|
||||
user.isPasswordCorrect(userData.uid, formData.password, data.req.ip),
|
||||
privileges.users.canEdit(data.req.uid, userData.uid),
|
||||
user.getUserField(userData.uid, 'email'),
|
||||
plugins.hooks.fire('filter:user.saveEmail', {
|
||||
@@ -46,6 +51,10 @@ Interstitials.email = async (data) => {
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!isAdminOrGlobalMod && !isPasswordCorrect) {
|
||||
await sleep(2000);
|
||||
}
|
||||
|
||||
if (formData.email && formData.email.length) {
|
||||
if (!allowed || !utils.isEmailValid(formData.email)) {
|
||||
throw new Error(error);
|
||||
@@ -60,6 +69,10 @@ Interstitials.email = async (data) => {
|
||||
await user.setUserField(userData.uid, 'email', formData.email);
|
||||
await user.email.confirmByUid(userData.uid);
|
||||
} else if (canEdit) {
|
||||
if (!isPasswordCorrect) {
|
||||
throw new Error('[[error:invalid-password]]');
|
||||
}
|
||||
|
||||
await user.email.sendValidationEmail(userData.uid, {
|
||||
email: formData.email,
|
||||
force: true,
|
||||
@@ -76,7 +89,7 @@ Interstitials.email = async (data) => {
|
||||
throw new Error('[[error:invalid-email]]');
|
||||
}
|
||||
|
||||
if (current) {
|
||||
if (current.length && (isPasswordCorrect || isAdminOrGlobalMod)) {
|
||||
// User explicitly clearing their email
|
||||
await user.email.remove(userData.uid, data.req.session.id);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
<div class="form-group">
|
||||
<label for="email">[[global:email]]</label>
|
||||
<input class="form-control" type="text" id="email" name="email" placeholder="{email}" value="{email}" />
|
||||
<p class="help-block">[[user:emailUpdate.change-instructions]]</p>
|
||||
</div>
|
||||
<p class="help-block">[[user:emailUpdate.change-instructions]]</p>
|
||||
|
||||
{{{ if update }}}
|
||||
<div class="form-group">
|
||||
<label for="password">[[register:password]]</label>
|
||||
<input class="form-control" type="password" id="password" name="password" />
|
||||
<p class="help-block">[[user:emailUpdate.password-challenge]]</p>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
Reference in New Issue
Block a user