added recoverPassword endpoints

This commit is contained in:
SrGooglo 2025-02-25 23:09:28 +00:00
parent 74704cede0
commit adbf694222
3 changed files with 120 additions and 17 deletions

View File

@ -2,22 +2,24 @@ import Account from "@classes/account"
import requiredFields from "@shared-utils/requiredFields"
export default {
middlewares: ["withAuthentication"],
//middlewares: ["withAuthentication"],
fn: async (req) => {
requiredFields(["old_password", "new_password"], req.body)
requiredFields(["new_password"], req.body)
await Account.changePassword(
{
user_id: req.auth.session.user_id,
user_id: req.auth?.session?.user_id ?? null,
old_password: req.body.old_password,
new_password: req.body.new_password,
log_comment: "Changed from password change request"
verificationToken: req.body.verificationToken,
code: req.body.code,
log_comment: "Changed from password change request",
},
req
req,
)
return {
message: "Password changed"
}
message: "Password changed",
}
},
}

View File

@ -0,0 +1,94 @@
import { User, PasswordRecover } from "@db_models"
import AuthToken from "@shared-classes/AuthToken"
import obscureEmail from "@shared-utils/obscureEmail"
import isEmail from "@shared-utils/isEmail"
function getClientDeviceData(req) {
const ip =
req.headers["x-forwarded-for"] ?? req.socket?.remoteAddress ?? req.ip
const userAgent = req.headers["user-agent"]
return { ip_address: ip, client: userAgent }
}
export default {
fn: async (req) => {
// find user by email or username
const { account } = req.body
const userSearchQuery = {}
if (isEmail(account)) {
userSearchQuery.email = account
} else {
userSearchQuery.username = account
}
const user = await User.findOne(userSearchQuery).select("+email")
if (!user) {
throw new OperationError(404, "User not found")
}
let passwordRecoverSession = await PasswordRecover.findOne({
user_id: user._id.toString(),
})
// check if session exist, and if it's expired
if (passwordRecoverSession) {
const now = new Date()
const expires = passwordRecoverSession.expires_at
// if not expired, thow a error
if (expires > now) {
throw new OperationError(
400,
"Password recovery session is still active",
)
} else {
// destroy session
await PasswordRecover.findOneAndDelete({
_id: passwordRecoverSession._id.toString(),
})
}
}
// expires in 5 minutes
const expiresIn = 1000 * 60 * 5
passwordRecoverSession = new PasswordRecover({
user_id: user._id.toString(),
created_at: new Date(),
expires_at: new Date(Date.now() + expiresIn),
code: global.nanoid(8),
...getClientDeviceData(req),
})
await passwordRecoverSession.save()
const verificationToken = await AuthToken.signToken({
recoverySessionId: passwordRecoverSession._id.toString(),
user_id: user._id.toString(),
})
ipc.invoke("ems", "apr:send", {
code: passwordRecoverSession.code,
created_at: passwordRecoverSession.created_at,
expires_at: passwordRecoverSession.expires_at,
user: user.toObject(),
...getClientDeviceData(req),
})
return {
user_id: user._id.toString(),
email: obscureEmail(user.email),
expires_at: passwordRecoverSession.expires_at,
expires_in: Math.floor(
(passwordRecoverSession.expires_at - Date.now()) / 1000 / 60,
),
code_length: passwordRecoverSession.code.toString().length,
verificationToken: verificationToken,
}
},
}

View File

@ -0,0 +1,7 @@
export default (email) => {
const checkIfIsEmail = (email) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
}
return checkIfIsEmail(email)
}