profile: unify password verification check

This commit is contained in:
Girish Ramakrishnan
2024-01-22 13:53:40 +01:00
parent 3220721f84
commit d7dda61775
4 changed files with 7 additions and 18 deletions

View File

@@ -27,7 +27,7 @@ async function passwordAuth(req, res, next) {
const verifyFunc = username.indexOf('@') === -1 ? users.verifyWithUsername : users.verifyWithEmail;
let [error, user] = await safe(verifyFunc(username, password, users.AP_WEBADMIN, { totpToken }));
let [error, user] = await safe(verifyFunc(username, password, users.AP_WEBADMIN, { totpToken, skipTotpCheck: false }));
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new HttpError(401, error.message));
if (error && error.reason === BoxError.NOT_FOUND) return next(new HttpError(401, 'Unauthorized'));
if (error) return next(new HttpError(500, error));

View File

@@ -1,7 +1,7 @@
'use strict';
exports = module.exports = {
authorize,
canEditProfile,
get,
setDisplayName,
setEmail,
@@ -25,7 +25,7 @@ const assert = require('assert'),
safe = require('safetydance'),
users = require('../users.js');
async function authorize(req, res, next) {
async function canEditProfile(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
const [error, profileConfig] = await safe(users.getProfileConfig());
@@ -66,12 +66,6 @@ async function setEmail(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
if ('email' in req.body && typeof req.body.email !== 'string') return next(new HttpError(400, 'email must be string'));
if (!req.body.password || typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be non empty string'));
const [verifyError] = await safe(users.verify(req.user.id, req.body.password, users.AP_WEBADMIN, { skipTotpCheck: true })); // just check password
if (verifyError) return next(BoxError.toHttpError(verifyError));
req.body.password = '<redacted>'; // this will prevent logs from displaying plain text password
const [error] = await safe(users.update(req.user, { email: req.body.email }, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
@@ -84,12 +78,6 @@ async function setFallbackEmail(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
if ('fallbackEmail' in req.body && typeof req.body.fallbackEmail !== 'string') return next(new HttpError(400, 'fallbackEmail must be string'));
if (!req.body.password || typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be non empty string'));
const [verifyError] = await safe(users.verify(req.user.id, req.body.password, users.AP_WEBADMIN, { skipTotpCheck: true })); // just check password
if (verifyError) return next(BoxError.toHttpError(verifyError));
req.body.password = '<redacted>'; // this will prevent logs from displaying plain text password
const [error] = await safe(users.update(req.user, { fallbackEmail: req.body.fallbackEmail }, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));

View File

@@ -167,6 +167,7 @@ async function del(req, res, next) {
async function verifyPassword(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.user, 'object');
if (typeof req.body.password !== 'string') return next(new HttpError(400, 'API call requires user password'));

View File

@@ -160,9 +160,9 @@ async function initializeExpressSync() {
// working off the user behind the provided token
router.get ('/api/v1/profile', token, authorizeUser, routes.profile.get);
router.post('/api/v1/profile/display_name', json, token, authorizeUser, routes.profile.authorize, routes.profile.setDisplayName);
router.post('/api/v1/profile/email', json, token, authorizeUser, routes.profile.authorize, routes.profile.setEmail);
router.post('/api/v1/profile/fallback_email', json, token, authorizeUser, routes.profile.authorize, routes.profile.setFallbackEmail);
router.post('/api/v1/profile/display_name', json, token, authorizeUser, routes.profile.canEditProfile, routes.profile.setDisplayName);
router.post('/api/v1/profile/email', json, token, authorizeUser, routes.profile.canEditProfile, routes.users.verifyPassword, routes.profile.setEmail);
router.post('/api/v1/profile/fallback_email', json, token, authorizeUser, routes.profile.canEditProfile, routes.users.verifyPassword, routes.profile.setFallbackEmail);
router.get ('/api/v1/profile/avatar/:identifier', routes.profile.getAvatar); // this is not scoped so it can used directly in img tag
router.post('/api/v1/profile/avatar', json, token, authorizeUser, (req, res, next) => { return typeof req.body.avatar === 'string' ? next() : multipart(req, res, next); }, routes.profile.setAvatar); // avatar is not exposed in LDAP. so it's personal and not locked
router.get ('/api/v1/profile/background_image', token, authorizeUser, routes.profile.getBackgroundImage);