Untitled
Anis
plain_text
a year ago
11 kB
7
Indexable
const sendOTPVerification = require("../../services/sendOTPVerification"); const User = require("../../models/User"); const { exclude, generateSignature, generatePassword, generateSalt, validatePassword, generateVerificationCode, checkOptValidity, checkTimeValidity, } = require("../../helpers"); const bcrypt = require("bcrypt"); const moment = require("moment"); const EXPIRE_TIME = 60 * 60 * 24 * 29 * 1000; // 29 Days // Create New User const userRegister = async (userInputs) => { try { const { phone, password, provider, country } = userInputs; let existingUser = await User.findOne({ phone }); if (existingUser) { // Case 1: User exists, phone unverified, delete the existing user if (existingUser?.phone_verified === 0) { await User.deleteOne({ phone: phone }); existingUser = null; } // Case 2: User exists, phone verified, and phone provider if ( existingUser?.phone_verified === 1 && existingUser?.provider === "phone" && provider === "phone" ) { return { status: false, message: "This phone number already exists!" }; } // Case 3: User exists, phone verified, different provider (prevent manual registration) // if ( // existingUser?.phone_verified === 1 && // existingUser?.provider !== "phone" && // provider === "phone" // ) { // return { // status: false, // message: `Please Try, Sign Up with ${capitalizeFirstLetter( // existingUser.provider // )}!`, // }; // } } const salt = await generateSalt(); const hashedPassword = await generatePassword(password, salt); let newUser = existingUser; if (!newUser) { // Create a new user if not exists newUser = new User({ phone, password: hashedPassword, salt, provider, country, }); await newUser.save(); } if (provider === "phone") { // Case 4: User is registered with email provider const otp = generateVerificationCode(6); const hashedOtp = await bcrypt.hash(otp, 10); // Save verify code await newUser.updateOne({ verify_code: hashedOtp }); // Send OTP const otpResponse = await sendOTPVerification(phone, otp); if (otpResponse === "0") { return { status: true, message: "OTP sent successfully!", }; } else if (otpResponse === "6") { return { status: false, message: "Your are provided wrong number!", }; } else { return { status: false, message: "Something went wrong!", }; } } ///////////===== Other Login Providers Not Handled Right Now =====/////////// // Case 5: User registered via social provider const accessToken = await generateSignature( { phone: newUser.phone, }, 60 * 60 * 24 * 30 // 30 Days ); const refreshToken = await generateSignature( { phone: newUser.phone, }, 60 * 60 * 24 * 60 // 30 Days ); const user = exclude(newUser.toObject(), [ "_id", "__v", "password", "salt", "verify_code", "provider", "forget_code", "createdAt", "updatedAt", "favorites", ]); return { status: true, message: "Login successfully!", data: { accessToken, refreshToken, expiresIn: new Date().setTime(new Date().getTime() + EXPIRE_TIME), ...user, role: "user", }, }; } catch (error) { console.error("Error", error); if (error.code === 11000 && error.keyPattern && error.keyPattern.email) { throw new Error("Email is already exist!"); } throw new Error("Failed to create user!"); } }; // User Sign In with Phone const signIn = async (userInfo) => { try { const { phone, password } = userInfo; let existingUser = await User.findOne({ phone }); if (!existingUser) { return { status: false, message: "Your credentials are incorrect!", }; } else { const validPassword = await validatePassword( password, existingUser.password, existingUser.salt ); if (validPassword) { const accessToken = await generateSignature( { phone: existingUser.phone, }, 60 * 60 * 24 * 30 // 30 Days ); const refreshToken = await generateSignature( { phone: existingUser.phone, }, 60 * 60 * 24 * 60 // 60 Days ); const user = exclude(existingUser.toObject(), [ "_id", "__v", "password", "salt", "verify_code", "provider", "forget_code", "createdAt", "updatedAt", ]); return { status: true, message: "Login successfully!", data: { accessToken, refreshToken, expiresIn: new Date().setTime(new Date().getTime() + EXPIRE_TIME), ...user, role: "user", }, }; } else { return { status: false, message: "Your credentials are incorrect!", }; } } } catch (error) { console.error("Error in Sign In:", error); throw new Error("Failed to user Sign In!"); } }; // Verify Phone const verifyPhoneOtp = async (optInfo) => { try { const { phone, otp } = optInfo; const findUser = await User.findOne({ phone }); if (!findUser) { return { status: false, message: "OTP is expired or incorrect!" }; } const hashedOtp = findUser.verify_code; let isValidOtp = false; const isValidTime = checkTimeValidity(findUser.updatedAt); if (!!hashedOtp) { isValidOtp = await checkOptValidity(otp, hashedOtp); } if (isValidOtp && isValidTime) { const userData = { phone_verified: 1, status: 1, verify_code: null, }; const verifiedUser = await User.findByIdAndUpdate( findUser._id, userData, { new: true } ); const accessToken = await generateSignature( { phone: verifiedUser.phone, }, 60 * 60 * 24 * 30 // 30 Days ); const refreshToken = await generateSignature( { phone: verifiedUser.phone, }, 60 * 60 * 24 * 60 // 60 Days ); const user = exclude(verifiedUser.toObject(), [ "password", "salt", "verify_code", "provider", "forget_code", "createdAt", "updatedAt", "_id", "__v", ]); return { status: true, data: { ...user, accessToken, refreshToken, expiresIn: new Date().setTime(new Date().getTime() + EXPIRE_TIME), role: "user", }, message: "Otp validated & sign in successfully!", }; } else { return { status: false, message: "OTP is expired or incorrect!" }; } } catch (error) { console.error("Error", error); throw new Error("Failed"); } }; // Get Access Token const getAccessToken = async (userInfo) => { try { const accessToken = await generateSignature( { email: userInfo.email, role: userInfo.role, }, 60 * 60 * 24 // 1 Day ); const refreshToken = await generateSignature( { email: userInfo.email, role: userInfo.role, }, 60 * 60 * 24 * 7 // 7 Days ); return { status: true, message: "Access Token refresh successfully!", data: { accessToken, refreshToken, expiresIn: new Date().setTime(new Date().getTime() + EXPIRE_TIME), }, }; } catch (error) { console.error("Error in Sign In:", error); throw new Error("Failed to Sign In user"); } }; // Resend OTP (Handle With Context - 1. Verify Code 2. Forget Code) const resendOTP = async (userInfo) => { try { const { phone, context } = userInfo; const existingUser = await User.findOne({ phone }); if (!existingUser) { return { status: false, message: "User not found!" }; } if (existingUser.phone_verified !== 0 && context === "verify_code") { return { status: false, message: "Phone is already verified!" }; } const otp = generateVerificationCode(6); const hashedOtp = await bcrypt.hash(otp, 10); // 2 minutes block time for each request if (!existingUser.resend_otp_block_timestamp) { const time = moment().add(2, "minutes").unix(); if (context === "verify_code") { await existingUser.updateOne({ verify_code: hashedOtp, resend_otp_block_timestamp: time, }); } else { await existingUser.updateOne({ forget_code: hashedOtp, resend_otp_block_timestamp: time, }); } } else { const currentTime = moment().unix(); const isBlocked = moment(currentTime).isBefore( existingUser.resend_otp_block_timestamp ); if (isBlocked) { return { status: false, message: "Try again after waiting for up to 2 minutes!", }; } else { const time = moment().add(2, "minutes").unix(); if (context === "verify_code") { await existingUser.updateOne({ verify_code: hashedOtp, resend_otp_block_timestamp: time, }); } else { await existingUser.updateOne({ forget_code: hashedOtp, resend_otp_block_timestamp: time, }); } } } // Send OTP const otpResponse = await sendOTPVerification(phone, otp); if (otpResponse === "0") { return { status: true, message: "New OTP sent successfully!", }; } else if (otpResponse === "6") { return { status: false, message: "Your are provided wrong number!", }; } else { return { status: false, message: "Something went wrong!", }; } } catch (error) { console.error("Error in Resend Verification Email:", error); throw new Error("Failed to resend verification email"); } };
Editor is loading...
Leave a Comment