280 lines
9.9 KiB
JavaScript
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};
|