feat: present a password challenge on email update flow

isekai-main
Julian Lam 3 years ago
parent 9ee1afbb0f
commit 7fcee42be9

@ -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>
Loading…
Cancel
Save