2023-09-21 14:00:04 +00:00
// @ts-check
/ * *
* === === === === === === === === === === === === === === === === === === === === === === === === === ===
* Imports
* === === === === === === === === === === === === === === === === === === === === === === === === === ===
* /
const fs = require ( "fs" ) ;
const http = require ( "http" ) ;
const varDatabaseDbHandler = require ( "../../../engine/utils/varDatabaseDbHandler" ) ;
const addDbEntry = require ( "../../../query/utils/addDbEntry" ) ;
const encrypt = require ( "../../../../functions/encrypt" ) ;
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
/ * *
* @ typedef { object } FunctionReturn
* @ property { boolean } success - Did the operation complete successfully or not ?
* @ property { {
* id : number ,
* first _name : string ,
* last _name : string ,
* } | null } user - User payload object : or "null"
* @ property { string } [ msg ] - Message
* @ property { string } [ error ] - Error Message
* @ property { string | number } [ social _id ] - Social Id
* @ property { string } [ social _platform ] - Social Platform
* @ property { object } [ payload ] - Payload
* @ property { boolean } [ alert ] - Alert
* @ property { * } [ newUser ] - New User
* /
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
const database = process . env . DSQL _DB _NAME || "" ;
const encryptionKey = process . env . DSQL _ENCRYPTION _KEY || "" ;
const encryptionSalt = process . env . DSQL _ENCRYPTION _SALT || "" ;
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
/ * *
* Handle Social User Auth on Datasquirel Database
* === === === === === === === === === === === === === === === === === === === === === === === === === ===
*
* @ description This function handles all social login logic after the social user
* has been authenticated and userpayload is present . The payload MUST contain the
* specified fields because this funciton will create a new user if the authenticated
* user does not exist .
*
* @ param { {
* database : string | null | undefined ,
* social _id : string | number ,
* email : string ,
* social _platform : string ,
* payload : {
* social _id : string | number ,
* email : string ,
* social _platform : string ,
* first _name : string ,
* last _name : string ,
* image : string ,
* image _thumbnail : string ,
* username : string ,
* } ,
* res : http . ServerResponse ,
* supEmail ? : string | null ,
* additionalFields ? : object ,
2024-10-18 04:15:04 +00:00
* dbSchema : DSQL _DatabaseSchemaType | undefined
2023-09-21 14:00:04 +00:00
* } } params - function parameters inside an object
*
* @ returns { Promise < FunctionReturn > } - Response object
* /
2024-10-14 06:49:01 +00:00
async function handleSocialDb ( {
social _id ,
email ,
social _platform ,
payload ,
res ,
supEmail ,
additionalFields ,
dbSchema ,
} ) {
const tableSchema = dbSchema ? . tables . find (
( tb ) => tb ? . tableName === "users"
) ;
2023-09-21 14:00:04 +00:00
try {
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
let existingSocialIdUser = await varDatabaseDbHandler ( {
database : database ? database : "datasquirel" ,
queryString : ` SELECT * FROM users WHERE social_id = ? AND social_login='1' AND social_platform = ? ` ,
queryValuesArray : [ social _id . toString ( ) , social _platform ] ,
} ) ;
if ( existingSocialIdUser && existingSocialIdUser [ 0 ] ) {
return await loginSocialUser ( {
user : existingSocialIdUser [ 0 ] ,
social _platform ,
res ,
database ,
additionalFields ,
} ) ;
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
const finalEmail = email ? email : supEmail ? supEmail : null ;
if ( ! finalEmail ) {
return {
success : false ,
user : null ,
msg : "No Email Present" ,
social _id ,
social _platform ,
payload ,
} ;
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
let existingEmailOnly = await varDatabaseDbHandler ( {
database : database ? database : "datasquirel" ,
queryString : ` SELECT * FROM users WHERE email = ? ` ,
queryValuesArray : [ finalEmail ] ,
tableSchema ,
} ) ;
if ( existingEmailOnly && existingEmailOnly [ 0 ] ) {
return {
success : false ,
user : null ,
msg : "This Email is already taken" ,
alert : true ,
} ;
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
const foundUser = await varDatabaseDbHandler ( {
database : database ? database : "datasquirel" ,
queryString : ` SELECT * FROM users WHERE email=' ${ finalEmail } ' AND social_login='1' AND social_platform=' ${ social _platform } ' AND social_id=' ${ social _id } ' ` ,
} ) ;
if ( foundUser && foundUser [ 0 ] ) {
return await loginSocialUser ( {
user : payload ,
social _platform ,
res ,
database ,
additionalFields ,
} ) ;
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
const socialHashedPassword = encrypt ( {
data : social _id . toString ( ) ,
encryptionKey ,
encryptionSalt ,
} ) ;
const data = {
social _login : "1" ,
verification _status : supEmail ? "0" : "1" ,
password : socialHashedPassword ,
} ;
Object . keys ( payload ) . forEach ( ( key ) => {
// @ts-ignore
data [ key ] = payload [ key ] ;
} ) ;
const newUser = await addDbEntry ( {
dbFullName : database ? database : "datasquirel" ,
tableName : "users" ,
duplicateColumnName : "email" ,
duplicateColumnValue : finalEmail ,
data : {
... data ,
email : finalEmail ,
} ,
encryptionKey ,
encryptionSalt ,
tableSchema ,
} ) ;
if ( newUser ? . insertId ) {
const newUserQueried = await varDatabaseDbHandler ( {
database : database ? database : "datasquirel" ,
queryString : ` SELECT * FROM users WHERE id=' ${ newUser . insertId } ' ` ,
} ) ;
if ( ! newUserQueried || ! newUserQueried [ 0 ] )
return {
success : false ,
user : null ,
msg : "User Insertion Failed!" ,
} ;
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
if ( supEmail && database ? . match ( /^datasquirel$/ ) ) {
/ * *
* Send email Verification
*
* @ description Send verification email to newly created agent
* /
let generatedToken = encrypt ( {
data : JSON . stringify ( {
id : newUser . insertId ,
email : supEmail ,
dateCode : Date . now ( ) ,
} ) ,
encryptionKey ,
encryptionSalt ,
} ) ;
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
return await loginSocialUser ( {
user : newUserQueried [ 0 ] ,
social _platform ,
res ,
database ,
additionalFields ,
} ) ;
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
} else {
2024-10-14 06:49:01 +00:00
console . log (
"Social User Failed to insert in 'handleSocialDb.js' backend function =>" ,
newUser
) ;
2023-09-21 14:00:04 +00:00
return {
success : false ,
user : null ,
msg : "Social User Failed to insert in 'handleSocialDb.js' backend function => " ,
newUser : newUser ,
} ;
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
} catch ( /** @type {*} */ error ) {
2024-10-14 06:49:01 +00:00
console . log (
"ERROR in 'handleSocialDb.js' backend function =>" ,
error . message
) ;
2023-09-21 14:00:04 +00:00
return {
success : false ,
user : null ,
error : error . message ,
} ;
// serverError({
// component: "/functions/backend/social-login/handleSocialDb.js - main-catch-error",
// message: error.message,
// user: { first_name, last_name },
// });
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
/ * *
* Function to login social user
* === === === === === === === === === === === === === === === === === === === === === === === === === ===
* @ description This function logs in the user after 'handleSocialDb' function finishes
* the user creation or confirmation process
*
* @ async
*
* @ param { object } params - function parameters inside an object
* @ param { {
* first _name : string ,
* last _name : string ,
* email : string ,
* social _id : string | number ,
* } } params . user - user object
* @ param { string } params . social _platform - Whether its "google" or "facebook" or "github"
* @ param { http . ServerResponse } params . res - Https response object
* @ param { string | null } params . database - Target Database
* @ param { object } [ params . additionalFields ] - Additional fields to be added to the user payload
*
* @ returns { Promise < {
* success : boolean ,
* user : { id : number , first _name : string , last _name : string } | null
* msg ? : string
* } > }
* /
2024-10-14 06:49:01 +00:00
async function loginSocialUser ( {
user ,
social _platform ,
res ,
database ,
additionalFields ,
} ) {
2023-09-21 14:00:04 +00:00
const foundUser = await varDatabaseDbHandler ( {
database : database ? database : "datasquirel" ,
queryString : ` SELECT * FROM users WHERE email=' ${ user . email } ' AND social_id=' ${ user . social _id } ' AND social_platform=' ${ social _platform } ' ` ,
} ) ;
2024-10-14 06:49:01 +00:00
let csrfKey =
Math . random ( ) . toString ( 36 ) . substring ( 2 ) +
"-" +
Math . random ( ) . toString ( 36 ) . substring ( 2 ) ;
2023-09-21 14:00:04 +00:00
if ( ! foundUser ? . [ 0 ] ) {
return {
success : false ,
user : null ,
msg : "User Not Found" ,
} ;
}
let userPayload = {
id : foundUser [ 0 ] . id ,
type : foundUser [ 0 ] . type || "" ,
stripe _id : foundUser [ 0 ] . stripe _id || "" ,
first _name : foundUser [ 0 ] . first _name ,
last _name : foundUser [ 0 ] . last _name ,
username : foundUser [ 0 ] . username ,
email : foundUser [ 0 ] . email ,
social _id : foundUser [ 0 ] . social _id ,
image : foundUser [ 0 ] . image ,
image _thumbnail : foundUser [ 0 ] . image _thumbnail ,
verification _status : foundUser [ 0 ] . verification _status ,
social _login : foundUser [ 0 ] . social _login ,
social _platform : foundUser [ 0 ] . social _platform ,
csrf _k : csrfKey ,
logged _in _status : true ,
date : Date . now ( ) ,
} ;
if ( additionalFields && Object . keys ( additionalFields ) . length > 0 ) {
Object . keys ( additionalFields ) . forEach ( ( key ) => {
// @ts-ignore
userPayload [ key ] = foundUser [ 0 ] [ key ] ;
} ) ;
}
let encryptedPayload = encrypt ( {
data : JSON . stringify ( userPayload ) ,
encryptionKey ,
encryptionSalt ,
} ) ;
if ( res ? . setHeader ) {
2024-10-14 06:49:01 +00:00
res . setHeader ( "Set-Cookie" , [
` datasquirelAuthKey= ${ encryptedPayload } ;samesite=strict;path=/;HttpOnly=true;Secure=true ` ,
` csrf= ${ csrfKey } ;samesite=strict;path=/;HttpOnly=true ` ,
] ) ;
2023-09-21 14:00:04 +00:00
}
////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////
return {
success : true ,
user : userPayload ,
} ;
}
module . exports = handleSocialDb ;