import AuthToken from "@shared-classes/AuthToken" import { UserConfig, MFASession, TosViolations } from "@db_models" import obscureEmail from "@shared-utils/obscureEmail" import Account from "@classes/account" export default async (req, res) => { if (req.body.refreshToken && req.body.authToken) { return await AuthToken.handleRefreshToken(req.body) } if (!req.body.username || !req.body.password) { return res.status(400).json({ error: "Missing username or password", }) } const user = await Account.loginStrategy({ username: req.body.username, password: req.body.password, }) const violation = await TosViolations.findOne({ user_id: user._id.toString(), }) if (violation) { return res.status(403).json({ error: "Terms of service violated", violation: violation.toObject(), }) } if (user.activated === false) { return res.status(401).json({ code: user.email, user_id: user._id.toString(), activation_required: true, }) } const userConfig = await UserConfig.findOne({ user_id: user._id.toString(), }).catch(() => { return {} }) if (userConfig && userConfig.values) { if (userConfig.values["auth:mfa"]) { let codeVerified = false // search if is already a mfa session let mfaSession = await MFASession.findOne({ user_id: user._id }) if (mfaSession) { if (!req.body.mfa_code) { await MFASession.deleteMany({ user_id: user._id }) } else { if (mfaSession.expires_at < new Date().getTime()) { await MFASession.deleteMany({ user_id: user._id }) throw new OperationError( 401, "MFA code expired, login again...", ) } if (mfaSession.code == req.body.mfa_code) { codeVerified = true await MFASession.deleteMany({ user_id: user._id }) } else { throw new OperationError( 401, "Invalid MFA code, try again...", ) } } } if (!codeVerified) { const mfa = { type: "email", user_id: user._id, code: Math.floor(Math.random() * 9000) + 1000, created_at: new Date().getTime(), // expires in 1 hour expires_at: new Date().getTime() + 60 * 60 * 1000, ip_address: req.headers["x-forwarded-for"] ?? req.socket?.remoteAddress ?? req.ip, client: req.headers["user-agent"], } // create a new mfa session mfaSession = new MFASession(mfa) await mfaSession.save() ipc.invoke("ems", "mfa:send", mfa) return { message: `MFA required, using [${mfa.type}] method.`, method: mfa.type, sended_to: obscureEmail(user.email), mfa_required: true, } } } } const authData = { date: new Date().getTime(), username: user.username, user_id: user._id.toString(), ip_address: req.headers["cf-connecting-ip"] ?? req.headers["x-forwarded-for"] ?? req.socket?.remoteAddress ?? req.ip, client: req.headers["user-agent"], } const token = await AuthToken.createAuthToken(authData) const refreshToken = await AuthToken.createRefreshToken( authData.user_id, token, ) // emit to ems to notify user for the new login, in the background try { global.queues.createJob("notify-new-login", { authData, minDate: new Date().getTime() - 3 * 30 * 24 * 60 * 60 * 1000, currentToken: token, }) } catch (error) { // whoipsi dupsi console.error(error) } return { token: token, refreshToken: refreshToken, expires_in: AuthToken.authStrategy.expiresIn, } }