EN-60: Adding simplified Sign Up/Login/Renew/Recover process.
This commit is contained in:
263
src/apps/public/account/services.js
Normal file
263
src/apps/public/account/services.js
Normal file
@@ -0,0 +1,263 @@
|
||||
"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( `${ROOT_PATH}/${LIB_PATH}/Misc.js` );
|
||||
const { emailEvent , EMAIL_EVENTS } = require( `${ROOT_PATH}/${HANDLERS_PATH}/MailClient` );
|
||||
const { create_account, already_exists, login, login_with_session_token, reset_password } = require( `${ROOT_PATH}/${HANDLERS_PATH}/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 },
|
||||
company_type : { type : 'string', enum : ["Shipper" , "Carrier"] },
|
||||
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', 'company_type', '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
|
||||
};
|
||||
|
||||
const AuthorizeJWT = async(req, res) => {
|
||||
try{
|
||||
if( validator.validate( req.body , login_account_schema ).valid ){
|
||||
const { email, password } = req.body;
|
||||
const user = await login( email, password );
|
||||
if( !user ){
|
||||
return res.status(401).send( { error : "Invalid credentials" } );
|
||||
}
|
||||
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
|
||||
} );
|
||||
}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, company_type, 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, company_type );
|
||||
|
||||
const content = { user_name : email };
|
||||
const receiver = email;
|
||||
// await emailEvent( EMAIL_EVENTS.ACCOUNT_CONFIRMED , receiver , content );
|
||||
console.log(
|
||||
content
|
||||
);
|
||||
return res.status(200).send( { msg : "User created successfully!" } );
|
||||
}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_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 : "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" });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { AuthorizeJWT, RenewJWT, TryCreateAccount, ConfirmAccount, RecoverPwd, ConfirmRecoverPwd};
|
||||
Reference in New Issue
Block a user