fix(v2): OTP is now only digits, v3, adding Account APP
This commit is contained in:
@@ -9,25 +9,11 @@ function dummy_middleware( req, res ){
|
|||||||
|
|
||||||
router.post('/register', dummy_middleware );
|
router.post('/register', dummy_middleware );
|
||||||
|
|
||||||
router.post('/authorize', dummy_middleware );
|
router.post('/authorize', async( req, res ) => {
|
||||||
|
|
||||||
router.get('/authorize/:session_token', dummy_middleware );
|
|
||||||
|
|
||||||
router.get('/check-account/:email', async( req, res ) => {
|
|
||||||
try{
|
|
||||||
const email = req.params.email;
|
|
||||||
const data = await Application.check_account( email );
|
|
||||||
return res.send( data );
|
|
||||||
}catch(error){
|
|
||||||
console.error( error );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
router.post('/signup', async(req,res) => {
|
|
||||||
try{
|
try{
|
||||||
const email = req.body.email;
|
const email = req.body.email;
|
||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
const data = await Application.getVerifyChecksum( email , password );
|
const data = await Application.authorize_credentials( email , password );
|
||||||
if( data.error ){
|
if( data.error ){
|
||||||
const error = data.error;
|
const error = data.error;
|
||||||
return res.status( error.code ).send( { error : error.msg } );
|
return res.status( error.code ).send( { error : error.msg } );
|
||||||
@@ -35,6 +21,53 @@ router.post('/signup', async(req,res) => {
|
|||||||
return res.send( data );
|
return res.send( data );
|
||||||
}catch(error){
|
}catch(error){
|
||||||
console.error( error );
|
console.error( error );
|
||||||
|
return res.status( 500 ).send( { error } );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
router.get('/authorize/:session_token', async( req, res ) => {
|
||||||
|
try{
|
||||||
|
const session_token = req.params.session_token;
|
||||||
|
const data = await Application.authorize_token( session_token );
|
||||||
|
if( data.error ){
|
||||||
|
const error = data.error;
|
||||||
|
return res.status( error.code ).send( { error : error.msg } );
|
||||||
|
}
|
||||||
|
return res.send( data );
|
||||||
|
}catch(error){
|
||||||
|
console.error( error );
|
||||||
|
return res.status( 500 ).send( { error } );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
router.get('/check-account/:email', async( req, res ) => {
|
||||||
|
try{
|
||||||
|
const email = req.params.email;
|
||||||
|
const data = await Application.check_account( email );
|
||||||
|
if( data.error ){
|
||||||
|
const error = data.error;
|
||||||
|
return res.status( error.code ).send( { error : error.msg } );
|
||||||
|
}
|
||||||
|
return res.send( data );
|
||||||
|
}catch(error){
|
||||||
|
console.error( error );
|
||||||
|
return res.status( 500 ).send( { error } );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
router.post('/signup', async(req,res) => {
|
||||||
|
try{
|
||||||
|
const email = req.body.email;
|
||||||
|
const password = req.body.password;
|
||||||
|
const data = await Application.genOTPChecksum( email, password, "signup" );
|
||||||
|
if( data.error ){
|
||||||
|
const error = data.error;
|
||||||
|
return res.status( error.code ).send( { error : error.msg } );
|
||||||
|
}
|
||||||
|
return res.send( data );
|
||||||
|
}catch(error){
|
||||||
|
console.error( error );
|
||||||
|
return res.status( 500 ).send( { error } );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
router.patch('/signup', async(req,res) => {
|
router.patch('/signup', async(req,res) => {
|
||||||
@@ -51,10 +84,41 @@ router.patch('/signup', async(req,res) => {
|
|||||||
return res.send( data );
|
return res.send( data );
|
||||||
}catch(error){
|
}catch(error){
|
||||||
console.error( error );
|
console.error( error );
|
||||||
|
return res.status( 500 ).send( { error } );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
router.post('/recover', dummy_middleware );
|
router.post('/recover', async(req,res) => {
|
||||||
router.patch('/recover', dummy_middleware );
|
try{
|
||||||
|
const email = req.body.email;
|
||||||
|
const password = req.body.password;
|
||||||
|
const data = await Application.genOTPChecksum( email, password, "recover" );
|
||||||
|
if( data.error ){
|
||||||
|
const error = data.error;
|
||||||
|
return res.status( error.code ).send( { error : error.msg } );
|
||||||
|
}
|
||||||
|
return res.send( data );
|
||||||
|
}catch(error){
|
||||||
|
console.error( error );
|
||||||
|
return res.status( 500 ).send( { error } );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
router.patch('/recover', async(req,res) => {
|
||||||
|
try{
|
||||||
|
const email = req.body.email;
|
||||||
|
const password = req.body.password;
|
||||||
|
const otp = req.body.otp;
|
||||||
|
const checksum = req.body.checksum;
|
||||||
|
const data = await Application.recover( email , password, otp, checksum);
|
||||||
|
if( data.error ){
|
||||||
|
const error = data.error;
|
||||||
|
return res.status( error.code ).send( { error : error.msg } );
|
||||||
|
}
|
||||||
|
return res.send( data );
|
||||||
|
}catch(error){
|
||||||
|
console.error( error );
|
||||||
|
return res.status( 500 ).send( { error } );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const { toSha256,
|
|||||||
pwdSecret,
|
pwdSecret,
|
||||||
genErrorResponse } = require('../Ports/Interfaces');
|
genErrorResponse } = require('../Ports/Interfaces');
|
||||||
|
|
||||||
class ApplicationLogic {
|
class Account {
|
||||||
constructor(){
|
constructor(){
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,13 +50,25 @@ class ApplicationLogic {
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getVerifyChecksum( email , password ){
|
async genOTPChecksum( email, password, reason="signup" ){
|
||||||
const otp = this.genOTP( email );
|
let event_id = reason;
|
||||||
const it_exists = await Repository.getByEmail( email );
|
|
||||||
|
if( reason === "signup" ){
|
||||||
|
event_id = "getchecksum:signup";
|
||||||
|
|
||||||
if( it_exists ){
|
const it_exists = await Repository.getByEmail( email );
|
||||||
return genErrorResponse( "Email already exists" );
|
if( it_exists ){
|
||||||
|
return genErrorResponse( "User already registered!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}else if( reason === "recover" ){
|
||||||
|
event_id = "getchecksum:recover";
|
||||||
|
}else{
|
||||||
|
return genErrorResponse( "OPT Event type not defined" , 500 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const otp = this.genOTP( email );
|
||||||
|
|
||||||
const content = { OTP : otp, user_name : email, email };
|
const content = { OTP : otp, user_name : email, email };
|
||||||
|
|
||||||
const checksum_entry = {
|
const checksum_entry = {
|
||||||
@@ -66,7 +78,9 @@ class ApplicationLogic {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const checksum = toSha256( JSON.stringify(checksum_entry)).slice(0, 32);
|
const checksum = toSha256( JSON.stringify(checksum_entry)).slice(0, 32);
|
||||||
publishEvent( "getchecksum" , content );
|
|
||||||
|
publishEvent( event_id , content );
|
||||||
|
|
||||||
return { checksum };
|
return { checksum };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +107,25 @@ class ApplicationLogic {
|
|||||||
return await this.authorize_credentials( email, password );
|
return await this.authorize_credentials( email, password );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async recover( email, password, otp, checksum ){
|
||||||
|
const user = await Repository.getByEmail( email );
|
||||||
|
|
||||||
|
if( !user ){
|
||||||
|
return genErrorResponse( "Email is not registered!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
const checksum_entry = {email, password, otp};
|
||||||
|
const recomputed_checksum = toSha256( JSON.stringify(checksum_entry)).slice(0, 32);
|
||||||
|
|
||||||
|
if( recomputed_checksum != checksum ){
|
||||||
|
return genErrorResponse( "Wrong OTP" );
|
||||||
|
}
|
||||||
|
|
||||||
|
await Repository.updatePassword( user.id, this.genSafePassword( password ) );
|
||||||
|
|
||||||
|
return await this.authorize_credentials( email, password );
|
||||||
|
}
|
||||||
|
|
||||||
async authorize_credentials( email, password ){
|
async authorize_credentials( email, password ){
|
||||||
const user = await Repository.findByEmailPassword( email, this.genSafePassword( password ) );
|
const user = await Repository.findByEmailPassword( email, this.genSafePassword( password ) );
|
||||||
|
|
||||||
@@ -128,6 +161,42 @@ class ApplicationLogic {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async authorize_token( token ){
|
||||||
|
const user = await Repository.findBySessionToken( token );
|
||||||
|
|
||||||
|
if( !user ){
|
||||||
|
return genErrorResponse( "Invalid Session Token", 401 );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
await Repository.addSessionToken( user.id, session_token, session_token_exp );
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = new ApplicationLogic();
|
module.exports = new Account();
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { getModel } = require('../../../../Shared/Models/Objection');
|
const { getModel } = require('../../../../Shared/Models/Objection');
|
||||||
const Model = getModel('users');
|
const Users = getModel('users');
|
||||||
const Sessions = getModel('users_sessions');
|
const Sessions = getModel('users_sessions');
|
||||||
const Companies = getModel('companies');
|
const Companies = getModel('companies');
|
||||||
|
|
||||||
class SpecificModelRepository{
|
class SpecificModelRepository{
|
||||||
constructor(){}
|
constructor(){}
|
||||||
|
|
||||||
async populateCompany( user ){
|
async populate( user ){
|
||||||
if( user.company_id ){
|
if( user.company_id ){
|
||||||
const company = await Companies.query().findById( user.company_id );
|
const company = await Companies.query().findById( user.company_id );
|
||||||
user.company = company;
|
user.company = company;
|
||||||
@@ -19,28 +19,29 @@ class SpecificModelRepository{
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getByEmail( email ){
|
async getByEmail( email ){
|
||||||
const user = await Model.query()
|
const user = await Users.query()
|
||||||
.select( "*" )
|
.select( "*" )
|
||||||
.where("email","=",email).first();
|
.where("email","=",email).first();
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createOne( email, safe_password ){
|
async createOne( email, safe_password ){
|
||||||
const user = await Model.query().insert({
|
const user = await Users.query().insert({
|
||||||
email,
|
email,
|
||||||
password : safe_password,
|
password : safe_password,
|
||||||
"name":"No name",
|
"name":"No name",
|
||||||
"last_name":"No lastname",
|
"last_name":"No lastname",
|
||||||
"createdAt" : new Date().toISOString()
|
"createdAt" : new Date().toISOString()
|
||||||
});
|
});
|
||||||
return this.populateCompany( user );
|
return await this.populate( user );
|
||||||
}
|
}
|
||||||
|
|
||||||
async findByEmailPassword( email, safe_password ){
|
async findByEmailPassword( email, safe_password ){
|
||||||
const user = await Model.query().select('*')
|
const user = await Users.query().select('*')
|
||||||
.where("email","=",email)
|
.where("email","=",email)
|
||||||
.where("password","=",safe_password)
|
.where("password","=",safe_password)
|
||||||
.first();
|
.first();
|
||||||
return this.populateCompany( user );
|
return await this.populate( user );
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateSessionToken( old_token, token, expiration ){
|
async updateSessionToken( old_token, token, expiration ){
|
||||||
@@ -55,6 +56,12 @@ class SpecificModelRepository{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updatePassword( userId , safe_password ){
|
||||||
|
return await Users.query()
|
||||||
|
.findById( userId )
|
||||||
|
.patch( { password : safe_password } );
|
||||||
|
}
|
||||||
|
|
||||||
async addSessionToken( userId , token, expiration ){
|
async addSessionToken( userId , token, expiration ){
|
||||||
const entry = await Sessions.query().select('*').where("user_id",'=',userId).first();
|
const entry = await Sessions.query().select('*').where("user_id",'=',userId).first();
|
||||||
const data = {
|
const data = {
|
||||||
@@ -71,6 +78,12 @@ class SpecificModelRepository{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findBySessionToken( token ){
|
||||||
|
const session = await Sessions.query().select("*").where("token","=",token).first();
|
||||||
|
const user = await Users.query().findById( session.user_id );
|
||||||
|
return await this.populate( user );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new SpecificModelRepository();
|
module.exports = new SpecificModelRepository();
|
||||||
@@ -29,8 +29,8 @@ async function onContactFromWebPage( data ){
|
|||||||
* Dictionary of event ids and handlers
|
* Dictionary of event ids and handlers
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"App:Account:getchecksum" : onChecksumGeneration,
|
"App:Account:getchecksum:signup" : onChecksumGeneration,
|
||||||
"App:Account:signupconfirmed":onAccountConfirmed,
|
"App:Account:signupconfirmed":onAccountConfirmed,
|
||||||
"App:Account:getchecksum:pwdreset":onPasswordReset,
|
"App:Account:getchecksum:recover":onPasswordReset,
|
||||||
"App:ContactEmail:getchecksum":onContactFromWebPage,
|
"App:ContactEmail:contact":onContactFromWebPage,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ const s3Client = new S3Client({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const secret = apiConfig.authentication.jwtSecret;
|
const secret = apiConfig.authentication.jwtSecret;
|
||||||
|
const tokenSecret = apiConfig.authentication.tokenSecret;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert string to sha256 string in hex
|
* Convert string to sha256 string in hex
|
||||||
* @param {*} text
|
* @param {*} text
|
||||||
@@ -28,12 +30,14 @@ function toSha256( text ){
|
|||||||
* @param {*} text
|
* @param {*} text
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function genKey( len = 6 , key="" ){
|
function genKey( len = 5 , key="" ){
|
||||||
if( len >= 64 ){
|
if( len >= 64 ){
|
||||||
throw "invalid key len";
|
throw "invalid key len";
|
||||||
}
|
}
|
||||||
const complete_string = toSha256( key + new Date() + secret );
|
const shacode = toSha256( key + new Date() + tokenSecret );
|
||||||
return complete_string.substr(0 , len );
|
const otp_hex = shacode.slice(0 , len );
|
||||||
|
const otp_dec = Number.parseInt( otp_hex , 16 );
|
||||||
|
return ""+otp_dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPagination( query ){
|
function getPagination( query ){
|
||||||
|
|||||||
Reference in New Issue
Block a user