From e2e1744824303248aa5d45e86c8eabf8ba0baabb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20U=C5=9Fakl=C4=B1?= Date: Mon, 19 Jan 2026 18:40:48 -0500 Subject: [PATCH] User create / registeration queue refactor (#13905) * feat: add options parameter to User.create add emailVerification: ('send'|'verify'|'skip') param to User.create to control email verification add a new method User.createOrQueue(). store options that will be passed to User.create() when registration is accepted in _opts If there is no password passed to registration queue(SSO register) don't store hashedPassword removed the isFirstUser hack in user.create, when creating the admin user in install.js passing `emailVerification: 'verify'` to immediately verify the email, same with all the hacks in tests auth: if an SSO plugin sends back an info object, redirect to root and display the message * refactor: make function private * refactor: destruct return * test: fix flag test * test: group tests * feat: show ssoIcon if available in register queue * add icon/title --- src/controllers/authentication.js | 24 ++-------- src/controllers/helpers.js | 3 ++ src/install.js | 2 + src/routes/authentication.js | 9 ++-- src/user/approval.js | 58 ++++++++++++++++++++++--- src/user/create.js | 47 ++++++++++++-------- src/views/admin/manage/registration.tpl | 3 ++ test/api.js | 9 ++-- test/authentication.js | 18 ++++---- test/controllers-admin.js | 2 +- test/controllers.js | 36 ++++++++------- test/emailer.js | 5 ++- test/flags.js | 4 +- test/groups.js | 4 ++ test/socket.io.js | 6 +-- test/user.js | 44 ++++++++++--------- test/user/reset.js | 14 +++--- 17 files changed, 176 insertions(+), 112 deletions(-) diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 5cd6ee0d24..17657c47ef 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -41,13 +41,11 @@ async function registerAndLoginUser(req, res, userData) { return; } - const queue = await user.shouldQueueUser(req.ip); - const result = await plugins.hooks.fire('filter:register.shouldQueue', { req, res, userData, queue }); - if (result.queue) { - return await addToApprovalQueue(req, userData); + const { queued, uid, message } = await user.createOrQueue(req, userData); + if (queued) { + return { message }; } - const uid = await user.create(userData); if (res.locals.processLogin) { const hasLoginPrivilege = await privileges.global.can('local:login', uid); if (hasLoginPrivilege) { @@ -125,22 +123,6 @@ authenticationController.register = async function (req, res) { } }; -async function addToApprovalQueue(req, userData) { - userData.ip = req.ip; - await user.addToApprovalQueue(userData); - let message = '[[register:registration-added-to-queue]]'; - if (meta.config.showAverageApprovalTime) { - const average_time = await db.getObjectField('registration:queue:approval:times', 'average'); - if (average_time > 0) { - message += ` [[register:registration-queue-average-time, ${Math.floor(average_time / 60)}, ${Math.floor(average_time % 60)}]]`; - } - } - if (meta.config.autoApproveTime > 0) { - message += ` [[register:registration-queue-auto-approve-time, ${meta.config.autoApproveTime}]]`; - } - return { message: message }; -} - authenticationController.registerComplete = async function (req, res) { try { // For the interstitials that respond, execute the callback with the form body diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js index 97ff1a3129..f3ba8a4f0d 100644 --- a/src/controllers/helpers.js +++ b/src/controllers/helpers.js @@ -1,6 +1,7 @@ 'use strict'; const nconf = require('nconf'); +const winston = require('winston'); const validator = require('validator'); const querystring = require('querystring'); const _ = require('lodash'); @@ -23,8 +24,10 @@ const url = nconf.get('url'); helpers.noScriptErrors = async function (req, res, error, httpStatus) { if (req.body.noscript !== 'true') { if (typeof error === 'string') { + winston.error(`${new Error(error).stack}`); return res.status(httpStatus).send(error); } + winston.error(`${new Error(JSON.stringify(error)).stack}`); return res.status(httpStatus).json(error); } const middleware = require('../middleware'); diff --git a/src/install.js b/src/install.js index 064d5d77ff..856732f631 100644 --- a/src/install.js +++ b/src/install.js @@ -366,6 +366,8 @@ async function createAdmin() { username: results.username, password: results.password, email: results.email, + }, { + emailVerification: 'verify', }); await Groups.join('administrators', adminUid); await Groups.show('administrators'); diff --git a/src/routes/authentication.js b/src/routes/authentication.js index a4290544a1..ab523d08e6 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -121,7 +121,7 @@ Auth.reloadRoutes = async function (params) { // passport seems to remove `req.session.returnTo` after it redirects req.session.registration.returnTo = req.session.next || req.session.returnTo; - passport.authenticate(strategy.name, (err, user) => { + passport.authenticate(strategy.name, (err, user, info) => { if (err) { if (req.session && req.session.registration) { delete req.session.registration; @@ -133,7 +133,10 @@ Auth.reloadRoutes = async function (params) { if (req.session && req.session.registration) { delete req.session.registration; } - return helpers.redirect(res, strategy.failureUrl !== undefined ? strategy.failureUrl : '/login'); + if (info && info.message) { + return helpers.redirect(res, `/?register=${encodeURIComponent(info.message)}`); + } + return helpers.redirect(res, strategy.failureUrl || '/login'); } res.locals.user = user; @@ -149,7 +152,7 @@ Auth.reloadRoutes = async function (params) { return next(err); } - helpers.redirect(res, strategy.successUrl !== undefined ? strategy.successUrl : '/'); + helpers.redirect(res, strategy.successUrl || '/'); }); }); }); diff --git a/src/user/approval.js b/src/user/approval.js index 5067239d8a..f8470ebb65 100644 --- a/src/user/approval.js +++ b/src/user/approval.js @@ -22,6 +22,18 @@ module.exports = function (User) { } }), null, true); + User.createOrQueue = async function (req, userData, opts = {}) { + const queue = await User.shouldQueueUser(req.ip); + const result = await plugins.hooks.fire('filter:register.shouldQueue', { req, userData, queue }); + if (result.queue) { + await User.addToApprovalQueue({ ...userData, ip: req.ip, _opts: JSON.stringify(opts) }); + return { queued: true, message: await getRegistrationQueuedMessage() }; + } + + const uid = await User.create(userData, opts); + return { queued: false, uid }; + }; + User.addToApprovalQueue = async function (userData) { userData.username = userData.username.trim(); userData.userslug = slugify(userData.username); @@ -31,9 +43,12 @@ module.exports = function (User) { username: userData.username, email: userData.email, ip: userData.ip, - hashedPassword: hashedPassword, + _opts: userData._opts || '{}', }; - const results = await plugins.hooks.fire('filter:user.addToApprovalQueue', { data: data, userData: userData }); + if (hashedPassword) { + data.hashedPassword = hashedPassword; + } + const results = await plugins.hooks.fire('filter:user.addToApprovalQueue', { data, userData }); await db.setObject(`registration:queue:name:${userData.username}`, results.data); await db.sortedSetAdd('registration:queue', Date.now(), userData.username); await sendNotificationToAdmins(userData.username); @@ -69,12 +84,15 @@ module.exports = function (User) { if (!userData) { throw new Error('[[error:invalid-data]]'); } + const opts = parseCreateOptions(userData); const creation_time = await db.sortedSetScore('registration:queue', username); - const uid = await User.create(userData); - await User.setUserFields(uid, { - password: userData.hashedPassword, - 'password:shaWrapped': 1, - }); + const uid = await User.create(userData, opts); + if (userData.hashedPassword) { + await User.setUserFields(uid, { + password: userData.hashedPassword, + 'password:shaWrapped': 1, + }); + } await removeFromQueue(username); await markNotificationRead(username); await plugins.hooks.fire('filter:register.complete', { uid: uid }); @@ -90,6 +108,18 @@ module.exports = function (User) { return uid; }; + function parseCreateOptions(userData) { + let opts = {}; + try { + opts = JSON.parse(userData._opts || '{}'); + delete userData._opts; + return opts; + } catch (err) { + winston.error(`[user.acceptRegistration] Failed to parse create options for queued user ${userData.username}: ${err.stack}`); + return {}; + } + } + async function markNotificationRead(username) { const nid = `new-register:${username}`; const uids = await groups.getMembers('administrators', 0, -1); @@ -120,6 +150,20 @@ module.exports = function (User) { return false; }; + async function getRegistrationQueuedMessage() { + let message = '[[register:registration-added-to-queue]]'; + if (meta.config.showAverageApprovalTime) { + const average_time = await db.getObjectField('registration:queue:approval:times', 'average'); + if (average_time > 0) { + message += ` [[register:registration-queue-average-time, ${Math.floor(average_time / 60)}, ${Math.floor(average_time % 60)}]]`; + } + } + if (meta.config.autoApproveTime > 0) { + message += ` [[register:registration-queue-auto-approve-time, ${meta.config.autoApproveTime}]]`; + } + return message; + }; + User.getRegistrationQueue = async function (start, stop) { const data = await db.getSortedSetRevRangeWithScores('registration:queue', start, stop); const keys = data.filter(Boolean).map(user => `registration:queue:name:${user.value}`); diff --git a/src/user/create.js b/src/user/create.js index ee4c3f27e7..c66de5c174 100644 --- a/src/user/create.js +++ b/src/user/create.js @@ -12,7 +12,8 @@ const meta = require('../meta'); const analytics = require('../analytics'); module.exports = function (User) { - User.create = async function (data) { + User.create = async function (data, opts = {}) { + opts = { emailVerification: 'send', ...opts }; data.username = data.username.trim(); data.userslug = slugify(data.username); if (data.email !== undefined) { @@ -27,7 +28,7 @@ module.exports = function (User) { } try { - return await create(data); + return await create(data, opts); } finally { await db.deleteObjectFields('locks', [data.username, data.email]); } @@ -40,7 +41,7 @@ module.exports = function (User) { } } - async function create(data) { + async function create(data, opts) { const timestamp = data.timestamp || Date.now(); let userData = { @@ -73,7 +74,6 @@ module.exports = function (User) { userData = results.user; const uid = await db.incrObjectField('global', 'nextUid'); - const isFirstUser = uid === 1; userData.uid = uid; await db.setObject(`user:${uid}`, userData); @@ -103,20 +103,8 @@ module.exports = function (User) { User.updateDigestSetting(userData.uid, meta.config.dailyDigestFreq), ]); - if (data.email && isFirstUser) { - await User.setUserField(uid, 'email', data.email); - await User.email.confirmByUid(userData.uid); - } + await handleEmailVerification(uid, data.email, data.token, opts.emailVerification); - if (data.email && userData.uid > 1) { - if (!data.token || !await User.isInviteTokenValid(data.token, data.email)) { - await User.email.sendValidationEmail(userData.uid, { - email: data.email, - template: 'welcome', - subject: `[[email:welcome-to, ${meta.config.title || meta.config.browserTitle || 'NodeBB'}]]`, - }).catch(err => winston.error(`[user.create] Validation email failed to send\n[emailer.send] ${err.stack}`)); - } - } if (userNameChanged) { await User.notifications.sendNameChangeNotification(userData.uid, userData.username); } @@ -138,6 +126,31 @@ module.exports = function (User) { ]); } + async function handleEmailVerification(uid, email, token, method) { + if (email) { + switch (method) { + case 'verify': + await User.setUserField(uid, 'email', email); + await User.email.confirmByUid(uid); + break; + case 'send': + if (!token || !await User.isInviteTokenValid(token, email)) { + await User.email.sendValidationEmail(uid, { + email: email, + template: 'welcome', + subject: `[[email:welcome-to, ${meta.config.title || meta.config.browserTitle || 'NodeBB'}]]`, + }).catch(err => winston.error(`[user.create] Validation email failed to send\n[emailer.send] ${err.stack}`)); + } + break; + case 'skip': + // explicitly do nothing + break; + default: + throw new Error(`Invalid email verification mode: ${method}`); + } + } + } + User.isDataValid = async function (userData) { if (userData.email && !utils.isEmailValid(userData.email)) { throw new Error('[[error:invalid-email]]'); diff --git a/src/views/admin/manage/registration.tpl b/src/views/admin/manage/registration.tpl index d301da1b08..9eaf75c24f 100644 --- a/src/views/admin/manage/registration.tpl +++ b/src/views/admin/manage/registration.tpl @@ -35,6 +35,9 @@ {{{ end }}} {{{ end }}} {./username} + {{{ if ./sso }}} + + {{{ end }}} {{{ if ./emailSpam }}} diff --git a/test/api.js b/test/api.js index 0137d29fd6..5e98d9f00c 100644 --- a/test/api.js +++ b/test/api.js @@ -185,13 +185,10 @@ describe('API', async () => { } // Create sample users - const adminUid = await user.create({ username: 'admin', password: '123456' }); - const unprivUid = await user.create({ username: 'unpriv', password: '123456' }); + const adminUid = await user.create({ username: 'admin', password: '123456', email: 'test@example.org' }, { emailVerification: 'verify' }); + const unprivUid = await user.create({ username: 'unpriv', password: '123456', email: 'unpriv@example.org' }, { emailVerification: 'verify' }); const emailConfirmationUid = await user.create({ username: 'emailConf', email: 'emailConf@example.org' }); - await user.setUserField(adminUid, 'email', 'test@example.org'); - await user.setUserField(unprivUid, 'email', 'unpriv@example.org'); - await user.email.confirmByUid(adminUid); - await user.email.confirmByUid(unprivUid); + mocks.get['/api/confirm/{code}'][0].example = await db.get(`confirm:byUid:${emailConfirmationUid}`); for (let x = 0; x < 4; x++) { diff --git a/test/authentication.js b/test/authentication.js index 4f72a9a705..7fa44b964b 100644 --- a/test/authentication.js +++ b/test/authentication.js @@ -20,19 +20,19 @@ describe('authentication', () => { let regularUid; const dummyEmailerHook = async (data) => {}; - before((done) => { + before(async () => { // Attach an emailer hook so related requests do not error plugins.hooks.register('authentication-test', { hook: 'static:email.send', method: dummyEmailerHook, }); - user.create({ username: 'regular', password: 'regularpwd', email: 'regular@nodebb.org' }, (err, uid) => { - assert.ifError(err); - regularUid = uid; - assert.strictEqual(uid, 1); - done(); + regularUid = await user.create({ + username: 'regular', password: 'regularpwd', email: 'regular@nodebb.org', + }, { + emailVerification: 'verify', }); + assert.strictEqual(regularUid, 1); }); after(() => { @@ -393,9 +393,9 @@ describe('authentication', () => { it('should be able to login with email', async () => { const email = 'ginger@nodebb.org'; - const uid = await user.create({ username: 'ginger', password: '123456', email }); - await user.setUserField(uid, 'email', email); - await user.email.confirmByUid(uid); + const uid = await user.create({ username: 'ginger', password: '123456', email }, { + emailVerification: 'verify', + }); const { response } = await helpers.loginUser('ginger@nodebb.org', '123456'); assert.equal(response.statusCode, 200); }); diff --git a/test/controllers-admin.js b/test/controllers-admin.js index a7206711b0..154fec69a8 100644 --- a/test/controllers-admin.js +++ b/test/controllers-admin.js @@ -4,8 +4,8 @@ const async = require('async'); const assert = require('assert'); const nconf = require('nconf'); -const request = require('../src/request'); const db = require('./mocks/databasemock'); +const request = require('../src/request'); const categories = require('../src/categories'); const topics = require('../src/topics'); const user = require('../src/user'); diff --git a/test/controllers.js b/test/controllers.js index 62a28c1080..c6cab42b2e 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -39,9 +39,9 @@ describe('Controllers', () => { }); cid = category.cid; - fooUid = await user.create({ username: 'foo', password: 'barbar', gdpr_consent: true }); - await user.setUserField(fooUid, 'email', 'foo@test.com'); - await user.email.confirmByUid(fooUid); + fooUid = await user.create({ username: 'foo', password: 'barbar', gdpr_consent: true, email: 'foo@test.com' }, { + emailVerification: 'verify', + }); adminUid = await user.create({ username: 'admin', password: 'barbar', gdpr_consent: true }); await groups.join('administrators', adminUid); @@ -395,9 +395,9 @@ describe('Controllers', () => { it('should remove current email (only allowed if email not required)', async () => { meta.config.requireEmailAddress = 0; - const uid = await user.create({ username: 'interstiuser5' }); - await user.setUserField(uid, 'email', 'interstiuser5@nodebb.org'); - await user.email.confirmByUid(uid); + const uid = await user.create({ + username: 'interstiuser5', email: 'interstiuser5@nodebb.org', + }, { emailVerification: 'verify' }); const result = await user.interstitials.email({ userData: { uid: uid, updateEmail: true }, @@ -418,9 +418,11 @@ describe('Controllers', () => { it('should require a password (if one is set) for email change', async () => { try { const [username, password] = [utils.generateUUID().slice(0, 10), utils.generateUUID()]; - const uid = await user.create({ username, password }); - await user.setUserField(uid, 'email', `${username}@nodebb.org`); - await user.email.confirmByUid(uid); + const uid = await user.create({ + username, password, email: `${username}@nodebb.org`, + }, { + emailVerification: 'verify', + }); const result = await user.interstitials.email({ userData: { uid: uid, updateEmail: true }, @@ -441,9 +443,11 @@ describe('Controllers', () => { try { const [username, password] = [utils.generateUUID().slice(0, 10), utils.generateUUID()]; - const uid = await user.create({ username, password }); - await user.setUserField(uid, 'email', `${username}@nodebb.org`); - await user.email.confirmByUid(uid); + const uid = await user.create({ + username, password, email: `${username}@nodebb.org`, + }, { + emailVerification: 'verify', + }); const result = await user.interstitials.email({ userData: { uid: uid, updateEmail: true }, @@ -463,9 +467,11 @@ describe('Controllers', () => { it('should successfully issue validation request if the correct password is passed in', async () => { const [username, password] = [utils.generateUUID().slice(0, 10), utils.generateUUID()]; - const uid = await user.create({ username, password }); - await user.setUserField(uid, 'email', `${username}@nodebb.org`); - await user.email.confirmByUid(uid); + const uid = await user.create({ + username, password, email: `${username}@nodebb.org`, + }, { + emailVerification: 'verify', + }); const result = await user.interstitials.email({ userData: { uid: uid, updateEmail: true }, diff --git a/test/emailer.js b/test/emailer.js index 35f82b0ecc..36aa96c89a 100644 --- a/test/emailer.js +++ b/test/emailer.js @@ -148,8 +148,9 @@ describe('emailer', () => { let recipientUid; before(async () => { - recipientUid = await user.create({ username: 'recipient', email: 'test@example.org' }); - await user.email.confirmByUid(recipientUid); + recipientUid = await user.create({ username: 'recipient', email: 'test@example.org' }, { + emailVerification: 'verify', + }); }); it('should not send email to a banned user', async () => { diff --git a/test/flags.js b/test/flags.js index aad4802e7a..84c9cd6919 100644 --- a/test/flags.js +++ b/test/flags.js @@ -38,7 +38,9 @@ describe('Flags', () => { }); // Create some stuff to flag - uid1 = await User.create({ username: 'testUser', password: 'abcdef', email: 'b@c.com' }); + uid1 = await User.create({ username: 'testUser', password: 'abcdef', email: 'b@c.com' }, { + emailVerification: 'verify', + }); adminUid = await User.create({ username: 'testUser2', password: 'abcdef', email: 'c@d.com' }); await Groups.join('administrators', adminUid); diff --git a/test/groups.js b/test/groups.js index 7b5ae4d73c..028d3f1b8c 100644 --- a/test/groups.js +++ b/test/groups.js @@ -73,12 +73,16 @@ describe('Groups', () => { testUid = await User.create({ username: 'testuser', email: 'b@c.com', + }, { + emailVerification: 'verify', }); adminUid = await User.create({ username: 'admin', email: 'admin@admin.com', password: '123456', + }, { + emailVerification: 'verify', }); await Groups.join('administrators', adminUid); }); diff --git a/test/socket.io.js b/test/socket.io.js index 0e725ad3be..2ef06eef4f 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -32,18 +32,16 @@ describe('socket.io', () => { before(async () => { const data = await Promise.all([ user.create({ username: 'admin', password: 'adminpwd' }), - user.create({ username: 'regular', password: 'regularpwd' }), + user.create({ username: 'regular', password: 'regularpwd', email: 'regular@test.com' }, { emailVerification: 'verify' }), categories.create({ name: 'Test Category', description: 'Test category created by testing script', }), ]); adminUid = data[0]; - await groups.join('administrators', data[0]); + await groups.join('administrators', adminUid); regularUid = data[1]; - await user.setUserField(regularUid, 'email', 'regular@test.com'); - await user.email.confirmByUid(regularUid); cid = data[2].cid; await topics.post({ diff --git a/test/user.js b/test/user.js index 16f0919366..af2b2f4e25 100644 --- a/test/user.js +++ b/test/user.js @@ -72,11 +72,12 @@ describe('User', () => { describe('.create(), when created', () => { it('should be created properly', async () => { - testUid = await User.create({ username: userData.username, password: userData.password }); + testUid = await User.create({ + username: userData.username, password: userData.password, email: userData.email, + }, { + emailVerification: 'verify', + }); assert.ok(testUid); - - await User.setUserField(testUid, 'email', userData.email); - await User.email.confirmByUid(testUid); }); it('should be created properly', async () => { @@ -694,12 +695,12 @@ describe('User', () => { let csrf_token; before(async () => { - const newUid = await User.create({ username: 'updateprofile', email: 'update@me.com', password: '123456' }); + const newUid = await User.create({ + username: 'updateprofile', email: 'update@me.com', password: '123456', + }, { + emailVerification: 'verify', + }); uid = newUid; - - await User.setUserField(uid, 'email', 'update@me.com'); - await User.email.confirmByUid(uid); - ({ jar, csrf_token } = await helpers.loginUser('updateprofile', '123456')); }); @@ -734,9 +735,11 @@ describe('User', () => { let uid; it('should update a user\'s profile', async () => { - uid = await User.create({ username: 'justforupdate', email: 'just@for.updated', password: '123456' }); - await User.setUserField(uid, 'email', 'just@for.updated'); - await User.email.confirmByUid(uid); + uid = await User.create({ + username: 'justforupdate', email: 'just@for.updated', password: '123456', + }, { + emailVerification: 'verify', + }); const data = { uid: uid, @@ -772,9 +775,9 @@ describe('User', () => { it('should not change the username to escaped version', async () => { const uid = await User.create({ username: 'ex\'ample_user', email: '13475@test.com', password: '123456', + }, { + emailVerification: 'verify', }); - await User.setUserField(uid, 'email', '13475@test.com'); - await User.email.confirmByUid(uid); const data = { uid: uid, @@ -1418,9 +1421,12 @@ describe('User', () => { it('should send digests', async () => { const oldValue = meta.config.includeUnverifiedEmails; meta.config.includeUnverifiedEmails = true; - const uid = await User.create({ username: 'digest' }); - await User.setUserField(uid, 'email', 'email@test.com'); - await User.email.confirmByUid(uid); + const uid = await User.create({ + username: 'digest', email: 'email@test.com', + }, { + emailVerification: 'verify', + }); + await User.digest.execute({ interval: 'day', subscribers: [uid], @@ -1893,7 +1899,7 @@ describe('User', () => { privateGroup: groups.create({ name: PRIVATE_GROUP, private: 1 }), hiddenGroup: groups.create({ name: HIDDEN_GROUP, hidden: 1 }), notAnInviter: User.create({ username: 'notAnInviter', password: COMMON_PW }), - inviter: User.create({ username: 'inviter', password: COMMON_PW }), + inviter: User.create({ username: 'inviter', password: COMMON_PW, email: 'invited@nodebb.org' }, { emailVerification: 'verify' }), admin: User.create({ username: 'adminInvite', password: COMMON_PW }), }); @@ -1901,12 +1907,10 @@ describe('User', () => { inviterUid = results.inviter; adminUid = results.admin; - await User.setUserField(inviterUid, 'email', 'inviter@nodebb.org'); await Promise.all([ groups.create({ name: OWN_PRIVATE_GROUP, ownerUid: inviterUid, private: 1 }), groups.join('administrators', adminUid), groups.join('cid:0:privileges:invite', inviterUid), - User.email.confirmByUid(inviterUid), ]); }); diff --git a/test/user/reset.js b/test/user/reset.js index a2c1d631cd..7ce3b60b1d 100644 --- a/test/user/reset.js +++ b/test/user/reset.js @@ -16,9 +16,11 @@ describe('Password reset (library methods)', () => { let uid; let code; before(async () => { - uid = await user.create({ username: 'resetuser', password: '123456' }); - await user.setUserField(uid, 'email', 'reset@me.com'); - await user.email.confirmByUid(uid); + uid = await user.create({ + username: 'resetuser', password: '123456', email: 'reset@me.com', + }, { + emailVerification: 'verify', + }); }); it('.generate() should generate a new reset code', (done) => { @@ -117,10 +119,10 @@ describe('locks', () => { let email; beforeEach(async () => { const [username, password] = [utils.generateUUID().slice(0, 10), utils.generateUUID()]; - uid = await user.create({ username, password }); email = `${username}@nodebb.org`; - await user.setUserField(uid, 'email', email); - await user.email.confirmByUid(uid); + uid = await user.create({ username, password, email }, { + emailVerification: 'verify', + }); }); it('should disallow reset request if one was made within the minute', async () => {