Files
ETAApi/v1/src/apps/public/account/services.js
2025-03-19 21:37:02 -06:00

280 lines
9.9 KiB
JavaScript

"use strict";
const jsonwebtoken = require('jsonwebtoken');
const { API_CONFIG, ROOT_PATH, LIB_PATH, HANDLERS_PATH } = process.env;
const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` );
const { genKey, toSha256 } = require( '../../../lib/Misc' );
const { emailEvent , EMAIL_EVENTS } = require( '../../../lib/Handlers/MailClient' );
const { create_account, already_exists, verify_driver_account, login, login_with_session_token, reset_password } = require( '../../../lib/Handlers/Account' );
const { Validator } = require( "jsonschema" );
const jwtSecret = apiConfig.authentication.jwtSecret;
const jwtTimeout = apiConfig.authentication.jwtTimeout;//Timeout in hours
const jwtRenewalTimeout = apiConfig.authentication.jwtRenewalTimeout;//Timeout in hours
const jwtOptions = apiConfig.authentication.jwtOptions;
const validator = new Validator();
const create_account_schema = {
type : 'object',
properties : {
email : { type : 'string' , maxLength : 256 },
password : { type : 'string', maxLength : 256},
otp : { type : 'string', maxLength : 6 },
checksum : { type : 'string', maxLength : 32 }
},
required : [ 'email', 'password' ]
};
const confirm_account_schema = {
type : 'object',
properties : create_account_schema.properties,//Same properties
required : [ 'email', 'password', 'otp', 'checksum' ]//Different requirements
};
const login_account_schema = {
type : 'object',
properties : create_account_schema.properties,//Same properties
required : [ 'email', 'password' ]//Different requirements
};
const password_recover_schema = create_account_schema;
const confirm_password_recover_schema = {
type : 'object',
properties : create_account_schema.properties,//Same properties
required : [ 'email', 'password', 'otp', 'checksum' ]//Different requirements
};
async function AuthorizeJWT_email_pwd( email , password ){
const user = await login( email, password );
if( !user ){
return null;
}
const current_date = new Date();
const iat = Math.floor( (current_date.getTime())/1000 );
const renewal_exp = ( iat + 3600*jwtRenewalTimeout ) * 1000;
/**
* Renew session token on every login event.
* Previous session token is lost
*/
const session_token = toSha256( `${new Date()}` );
const session_token_exp = new Date( renewal_exp );
user.session_token = session_token;
user.session_token_exp = session_token_exp;
await user.save();
const payload = {
iat: iat,
exp: iat + jwtTimeout * 3600,
aud: jwtOptions.audience,
iss: jwtOptions.audience,
sub: user.id,
};
const jwt = jsonwebtoken.sign( payload , jwtSecret );
return {
accessToken : jwt,
payload : payload,
session_token,
session_token_exp,
user : user
};
}
const AuthorizeJWT = async(req, res) => {
try{
if( validator.validate( req.body , login_account_schema ).valid ){
const { email, password } = req.body;
const retVal = await AuthorizeJWT_email_pwd( email , password );
if( !retVal ){
return res.status(401).send( { error : "Invalid credentials" } );
}
return res.send( retVal );
}else{
return res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
res.status(500).send({ error : "Login: Internal error" });
}
};
const RenewJWT = async(req, res) => {
try{
const login_session_token = req.params.session_token;
const user = await login_with_session_token( login_session_token );
if( !user ){
return res.status(401).send( { error : "Invalid or Expired Session Token" } );
}
const current_date = new Date();
const iat = Math.floor( (current_date.getTime())/1000 );
const renewal_exp = ( iat + 3600*jwtRenewalTimeout ) * 1000;
/**
* Renew session token on every login event.
* Previous session token is lost
*/
const session_token = toSha256( `${new Date()}` );
const session_token_exp = new Date( renewal_exp );
user.session_token = session_token;
user.session_token_exp = session_token_exp;
await user.save();
const payload = {
iat: iat,
exp: iat + jwtTimeout * 3600,
aud: jwtOptions.audience,
iss: jwtOptions.audience,
sub: user.id,
};
const jwt = jsonwebtoken.sign( payload , jwtSecret );
return res.status(200).send( {
accessToken : jwt,
payload : payload,
session_token,
session_token_exp,
user : user
} );
}catch( err ){
console.error( err );
res.status(500).send({ error : "Renew: Internal error" });
}
};
const TryCreateAccount = async(req, res) => {
try{
if( validator.validate( req.body , create_account_schema ).valid ){
const otp = genKey();
const { email : receiver , password } = req.body;
const email = receiver;
const it_exists = await already_exists( email );
if( it_exists ){
return res.status(400).send({ error : "Email already exists" });
}
const content = { OTP : otp, user_name : email };
const checksum_entry = {
email : receiver,
password,
otp
};
const checksum = toSha256( JSON.stringify(checksum_entry)).substr(0, 32);
await emailEvent( EMAIL_EVENTS.ACCOUNT_VERIFY , receiver , content );
console.log(
content
);
res.status(200).send( { checksum } );
}else{
res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
res.status(500).send({ error : "Account creation: Internal error" });
}
};
const ConfirmAccount = async(req, res) => {
try{
if( validator.validate( req.body , confirm_account_schema ).valid ){
const { email, password, otp, checksum } = req.body;
const it_exists = await already_exists( email );
if( it_exists ){
return res.status(400).send({ error : "User already registered!" });
}
const checksum_entry = {email, password, otp};
const recomputed_checksum = toSha256( JSON.stringify(checksum_entry)).substr(0, 32);
if( recomputed_checksum != checksum ){
return res.status(400).send({ error : "Wrong OTP" });
}
await create_account( email, password );
const content = { user_name : email };
const receiver = email;
await emailEvent( EMAIL_EVENTS.ACCOUNT_CONFIRMED , receiver , content );
const retVal = await AuthorizeJWT_email_pwd( email , password );
return res.send( retVal );
}else{
return res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
return res.status(500).send({ error : "Account creation: Internal error" });
}
};
const RecoverPwd = async(req, res) => {
try{
if( validator.validate( req.body , password_recover_schema ).valid ){
const otp = genKey();
const { email : receiver , password } = req.body;
const email = receiver;
const it_exists = await already_exists( email );
if( !it_exists ){
return res.status(400).send({ error : "Email is not registered!" });
}
const content = { OTP : otp, user_name : email };
const checksum_entry = {
email : receiver,
password,
otp
};
const checksum = toSha256( JSON.stringify(checksum_entry)).substr(0, 32);
await emailEvent( EMAIL_EVENTS.ACCOUNT_PWD_RESET , receiver , content );
console.log(
content
);
res.status(200).send( { checksum } );
}else{
res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
res.status(500).send({ error : "Password Recover: Internal error" });
}
};
const ConfirmRecoverPwd = async(req, res) => {
try{
if( validator.validate( req.body , confirm_password_recover_schema ).valid ){
const { email, password, otp, checksum } = req.body;
const it_exists = await already_exists( email );
if( !it_exists ){
return res.status(400).send({ error : "Email is not registered!" });
}
const checksum_entry = {email, password, otp};
const recomputed_checksum = toSha256( JSON.stringify(checksum_entry)).substr(0, 32);
if( recomputed_checksum != checksum ){
return res.status(400).send({ error : "Wrong OTP" });
}
await reset_password( email, password );
return res.status(200).send( { msg : "Password is reset!" } );
}else{
return res.status(400).send( { error : "Invalid request" } );
}
}catch( err ){
console.error( err );
return res.status(500).send({ error : "Password Recover Confirmation: Internal error" });
}
};
const checkAccount = async(req, res) => {
try{
const email = req.params.email;
const driver_account_val = await verify_driver_account( email );
return res.status(200).send( driver_account_val );
} catch ( err ){
console.error( err );
return res.status(500).send({ error : "AuthManagement: Internal error" });
}
};
module.exports = { AuthorizeJWT, RenewJWT, TryCreateAccount, ConfirmAccount, RecoverPwd, ConfirmRecoverPwd, checkAccount};