move various login routes under auth/

This commit is contained in:
Girish Ramakrishnan
2023-08-10 16:21:22 +05:30
parent 9ba6908764
commit 6c4aa605df
13 changed files with 162 additions and 149 deletions
+1 -107
View File
@@ -1,11 +1,6 @@
'use strict';
exports = module.exports = {
login,
logout,
passwordResetRequest,
passwordReset,
setupAccount,
getConfig,
updateDashboardDomain,
@@ -25,112 +20,11 @@ const assert = require('assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
cloudron = require('../cloudron.js'),
constants = require('../constants.js'),
debug = require('debug')('box:routes/cloudron'),
eventlog = require('../eventlog.js'),
HttpError = require('connect-lastmile').HttpError,
HttpSuccess = require('connect-lastmile').HttpSuccess,
platform = require('../platform.js'),
safe = require('safetydance'),
speakeasy = require('speakeasy'),
tokens = require('../tokens.js'),
translation = require('../translation.js'),
users = require('../users.js');
async function login(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
if ('type' in req.body && typeof req.body.type !== 'string') return next(new HttpError(400, 'type must be a string'));
const type = req.body.type || tokens.ID_WEBADMIN;
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || null;
const userAgent = req.headers['user-agent'] || '';
const auditSource = { authType: 'basic', ip };
let error = tokens.validateTokenType(type);
if (error) return next(new HttpError(400, error.message));
let token;
[error, token] = await safe(tokens.add({ clientId: type, identifier: req.user.id, expires: Date.now() + constants.DEFAULT_TOKEN_EXPIRATION_MSECS }));
if (error) return next(new HttpError(500, error));
await eventlog.add(req.user.ghost ? eventlog.ACTION_USER_LOGIN_GHOST : eventlog.ACTION_USER_LOGIN, auditSource, { userId: req.user.id, user: users.removePrivateFields(req.user) });
if (!req.user.ghost) safe(users.notifyLoginLocation(req.user, ip, userAgent, auditSource), { debug });
next(new HttpSuccess(200, token));
}
async function logout(req, res) {
assert.strictEqual(typeof req.token, 'object');
await eventlog.add(eventlog.ACTION_USER_LOGOUT, AuditSource.fromRequest(req), { userId: req.user.id, user: users.removePrivateFields(req.user) });
await safe(tokens.delByAccessToken(req.token.accessToken));
res.redirect('/');
}
async function passwordResetRequest(req, res, next) {
if (!req.body.identifier || typeof req.body.identifier !== 'string') return next(new HttpError(401, 'A identifier must be non-empty string'));
const [error] = await safe(users.sendPasswordResetByIdentifier(req.body.identifier, AuditSource.fromRequest(req)));
if (error && !(error.reason === BoxError.NOT_FOUND || error.reason === BoxError.CONFLICT)) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, {}));
}
async function passwordReset(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
if (typeof req.body.resetToken !== 'string') return next(new HttpError(400, 'Missing resetToken'));
if (typeof req.body.password !== 'string') return next(new HttpError(400, 'Missing password'));
let [error, userObject] = await safe(users.getByResetToken(req.body.resetToken));
if (error) return next(new HttpError(401, 'Invalid resetToken'));
if (!userObject) return next(new HttpError(401, 'Invalid resetToken'));
if (userObject.twoFactorAuthenticationEnabled) {
if (typeof req.body.totpToken !== 'string') return next(new HttpError(401, 'A totpToken must be provided'));
const verified = speakeasy.totp.verify({ secret: userObject.twoFactorAuthenticationSecret, encoding: 'base32', token: req.body.totpToken, window: 2 });
if (!verified) return next(new HttpError(401, 'Invalid totpToken'));
}
// if you fix the duration here, the emails and UI have to be fixed as well
if (Date.now() - userObject.resetTokenCreationTime > 7 * 24 * 60 * 60 * 1000) return next(new HttpError(401, 'Token expired'));
if (!userObject.username) return next(new HttpError(409, 'No username set'));
// setPassword clears the resetToken
[error] = await safe(users.setPassword(userObject, req.body.password, AuditSource.fromRequest(req)));
if (error && error.reason === BoxError.BAD_FIELD) return next(new HttpError(400, error.message));
if (error) return next(BoxError.toHttpError(error));
let result;
[error, result] = await safe(tokens.add({ clientId: tokens.ID_WEBADMIN, identifier: userObject.id, expires: Date.now() + constants.DEFAULT_TOKEN_EXPIRATION_MSECS }));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { accessToken: result.accessToken }));
}
async function setupAccount(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
if (!req.body.inviteToken || typeof req.body.inviteToken !== 'string') return next(new HttpError(400, 'inviteToken must be a non-empty string'));
if (!req.body.password || typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be a non-empty string'));
// only sent if profile is not locked
if ('username' in req.body && typeof req.body.username !== 'string') return next(new HttpError(400, 'username must be a non-empty string'));
if ('displayName' in req.body && typeof req.body.displayName !== 'string') return next(new HttpError(400, 'displayName must be a non-empty string'));
const [error, userObject] = await safe(users.getByInviteToken(req.body.inviteToken));
if (error) return next(new HttpError(401, 'Invalid inviteToken'));
if (!userObject) return next(new HttpError(401, 'Invalid inviteToken'));
const [setupAccountError, accessToken] = await safe(users.setupAccount(userObject, req.body, AuditSource.fromRequest(req)));
if (setupAccountError) return next(BoxError.toHttpError(setupAccountError));
next(new HttpSuccess(201, { accessToken }));
}
translation = require('../translation.js');
async function getConfig(req, res, next) {
const [error, cloudronConfig] = await safe(cloudron.getConfig());