diff --git a/client/package-lock.json b/client/package-lock.json index 65e9880..6f53dec 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -56,6 +56,7 @@ "socket.io": "^4.7.5", "socket.io-client": "^4.8.1", "sort-by": "^0.0.2", + "twilio": "^5.3.5", "uuid": "^11.0.2", "yup": "^1.4.0" }, @@ -2118,6 +2119,18 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "dev": true, @@ -2562,6 +2575,12 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/call-bind": { "version": "1.0.7", "license": "MIT", @@ -3011,6 +3030,15 @@ "dev": true, "license": "MIT" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.45", "dev": true, @@ -3996,6 +4024,8 @@ }, "node_modules/firebase": { "version": "10.14.1", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.14.1.tgz", + "integrity": "sha512-0KZxU+Ela9rUCULqFsUUOYYkjh7OM1EWdIfG6///MtXd0t2/uUIf0iNV5i0KariMhRQ5jve/OY985nrAXFaZeQ==", "license": "Apache-2.0", "dependencies": { "@firebase/analytics": "0.10.8", @@ -4388,6 +4418,19 @@ "version": "0.5.8", "license": "MIT" }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/idb": { "version": "7.1.1", "license": "ISC" @@ -4953,6 +4996,40 @@ "node": ">=6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "dev": true, @@ -4967,6 +5044,27 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "dev": true, @@ -5070,6 +5168,42 @@ "version": "4.0.8", "license": "MIT" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "license": "MIT" @@ -5079,6 +5213,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/lodash.reduce": { "version": "4.6.0", "license": "MIT" @@ -5304,7 +5444,6 @@ }, "node_modules/object-inspect": { "version": "1.13.2", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5832,6 +5971,21 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "dev": true, @@ -7137,6 +7291,12 @@ "loose-envify": "^1.1.0" } }, + "node_modules/scmp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==", + "license": "BSD-3-Clause" + }, "node_modules/scroll-into-view-if-needed": { "version": "3.1.0", "license": "MIT", @@ -7205,7 +7365,6 @@ }, "node_modules/side-channel": { "version": "1.0.6", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -7635,6 +7794,24 @@ "version": "2.8.0", "license": "0BSD" }, + "node_modules/twilio": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-5.3.5.tgz", + "integrity": "sha512-f/sA1Yd6TyIzfcq0u4QDGU+93afwswsJB+rf3T08tvBAMobBDVR3DfGREwJr5jp8xUic0qWa7GbJidk16NA4bg==", + "license": "MIT", + "dependencies": { + "axios": "^1.7.4", + "dayjs": "^1.11.9", + "https-proxy-agent": "^5.0.0", + "jsonwebtoken": "^9.0.2", + "qs": "^6.9.4", + "scmp": "^2.1.0", + "xmlbuilder": "^13.0.2" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "dev": true, @@ -8077,6 +8254,15 @@ } } }, + "node_modules/xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, "node_modules/xmlhttprequest-ssl": { "version": "2.1.2", "engines": { diff --git a/client/package.json b/client/package.json index d4a1f73..df5e27c 100644 --- a/client/package.json +++ b/client/package.json @@ -58,6 +58,7 @@ "socket.io": "^4.7.5", "socket.io-client": "^4.8.1", "sort-by": "^0.0.2", + "twilio": "^5.3.5", "uuid": "^11.0.2", "yup": "^1.4.0" }, diff --git a/client/src/App.jsx b/client/src/App.jsx index 67e6e81..aea07b7 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -44,6 +44,7 @@ import Collab from "./component/Collab"; import Ai from "./component/Ai"; import FAQ from "./component/Faq"; import CreateBlog from "./component/CreateBlog"; +import LoginOTP from "./component/LoginPhone"; // Main Layout Component const Layout = ({ children, mode, setProgress, toggleMode, showAlert }) => { @@ -249,6 +250,7 @@ function App() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/client/src/component/Login.jsx b/client/src/component/Login.jsx index fd81858..083aa63 100644 --- a/client/src/component/Login.jsx +++ b/client/src/component/Login.jsx @@ -16,7 +16,7 @@ import { useAuth } from '../contexts/authContext/index' const VITE_SERVER_PORT = import.meta.env.VITE_SERVER_PORT || "https://bitbox-uxbo.onrender.com"; -const Login = ({ mode, showAlert, isloggedin, setloggedin }) => { +const Login = ({ mode, showAlert, loggedin, setloggedin }) => { const [credentials, setCredentials] = useState({ email: "", password: "" }); const [loading, setLoading] = useState(false); @@ -34,11 +34,12 @@ const Login = ({ mode, showAlert, isloggedin, setloggedin }) => { body: JSON.stringify(credentials), }); const json = await response.json(); - + console.log(json); + if (json.success) { localStorage.setItem("token", json.authtoken); toast.success("Login Successfully!"); - setloggedin(!isloggedin) + setloggedin(!loggedin) navigate("/"); } else { toast.error("Login failed!"); @@ -60,7 +61,7 @@ const Login = ({ mode, showAlert, isloggedin, setloggedin }) => { const onGoogleSignIn = async (e) => { e.preventDefault(); - if (!isloggedin) { + if (!loggedin) { try { setloggedin(true); @@ -74,21 +75,7 @@ const Login = ({ mode, showAlert, isloggedin, setloggedin }) => { setloggedin(false); // Reset logged-in state if sign-in fails } } - }; - document.querySelector('#login-btn').addEventListener('click', (event) => { - event.preventDefault(); - - const emailInput = document.getElementById('login-email'); - const rememberMeCheckbox = document.getElementById('login-remember'); - - if (rememberMeCheckbox.checked) { - localStorage.setItem('rememberedEmail', emailInput.value); - } else { - localStorage.removeItem('rememberedEmail'); - } - - // Continue with your existing login logic... - }); + }; return (
@@ -157,13 +144,28 @@ const Login = ({ mode, showAlert, isloggedin, setloggedin }) => {
- + + + + + @@ -236,7 +238,7 @@ const Login = ({ mode, showAlert, isloggedin, setloggedin }) => { Login.propTypes = { mode: PropTypes.string.isRequired, showAlert: PropTypes.func.isRequired, - isloggedin: PropTypes.bool.isRequired, + loggedin: PropTypes.bool.isRequired, setloggedin: PropTypes.func.isRequired, }; diff --git a/client/src/component/LoginPhone.jsx b/client/src/component/LoginPhone.jsx new file mode 100644 index 0000000..ffc96f4 --- /dev/null +++ b/client/src/component/LoginPhone.jsx @@ -0,0 +1,234 @@ +import PropTypes from "prop-types"; +import { useState } from "react"; +import { useNavigate, Link } from "react-router-dom"; +import { Input, Button, Spin } from "antd"; +import { + UserOutlined, + LockOutlined, + EyeInvisibleOutlined, + EyeTwoTone, + PhoneFilled +} from "@ant-design/icons"; +import "../css/Login.css"; +import toast from "react-hot-toast"; +import { useAuth } from '../contexts/authContext/index' + +const VITE_SERVER_PORT = + import.meta.env.VITE_SERVER_PORT || "https://bitbox-uxbo.onrender.com"; + +const LoginOTP = ({ mode, showAlert, loggedin, setloggedin }) => { + const [number, setNumber] = useState("") + const [loading, setLoading] = useState(false); + const [otpSent, setOtpSent] = useState(false); + const [otp, setOtp] = useState(""); + const credentials = "" + + const navigate = useNavigate(); + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + + try { + + const response = await fetch(`${VITE_SERVER_PORT}/api/auth/sendotp`, { + method: "POST", + credentials: 'include', + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({number: number}), + }); + + const res = await response.json() + + if(res.success){ + toast.success("OTP sent successfully") + setOtpSent(true); + } else { + toast.error("Error sending otp"); + console.log("error sending otp"); + } + } catch (error) { + toast.error(error) + } + + setLoading(false) + }; + + + const { userLoggedIn, setUserLoggedIn } = useAuth() + + const handleOtpSubmit = async (e) => { + e.preventDefault() + console.log("hii"); + + setLoading(true); + + try { + + const response = await fetch(`${VITE_SERVER_PORT}/api/auth/verifyotp`, { + method: "POST", + credentials: 'include', + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({otp: otp}), + }); + + const res = await response.json() + + if(!res.success){ + toast.error("incorrect OTP") + console.log("incorrect otp"); + } else { + // alert("User signed in successfully!"); + toast.success("User signed in successfully!") + setUserLoggedIn(true) + setloggedin(!loggedin) + navigate("/") + } + + } catch (error) { + console.log(error); + toast.error(error) + } + + setLoading(false) + + } + + return ( +
+ {userLoggedIn && navigate('/')} +
+
+
+

Login Using OTP

+ {/* Title Line */} + + + { + !otpSent && <> +
+ } + placeholder="Phone number" + name="phone" + value={number} + onChange={(e)=>setNumber(e.target.value)} + autoComplete="on" + className="h-10 text-xl" + style={{ + backgroundColor: mode === "dark" ? "black" : "white", + color: mode === "dark" ? "white" : "black", + }} + required + + /> +
+ + + + } + + { + otpSent && <> +
+ } + placeholder="OTP" + name="otp" + value={otp} + onChange={(e)=>setOtp(e.target.value)} + autoComplete="on" + className="h-10 text-xl" + style={{ + backgroundColor: mode === "dark" ? "black" : "white", + color: mode === "dark" ? "white" : "black", + }} + required + /> +
+ + + + } + +

+ Don't have an account? + + + {" "} Sign Up + +

+ + + +
+ +
+

+ WELCOME +
+ BACK! +

+

+ Please Sign In here +
+ with your real info +

+
+
+
+ ); +}; + +LoginOTP.propTypes = { + mode: PropTypes.string.isRequired, + showAlert: PropTypes.func.isRequired, + loggedin: PropTypes.bool.isRequired, + setloggedin: PropTypes.func.isRequired, +}; + +export default LoginOTP; diff --git a/client/src/component/Navbar.jsx b/client/src/component/Navbar.jsx index 4cce28f..4780b0e 100644 --- a/client/src/component/Navbar.jsx +++ b/client/src/component/Navbar.jsx @@ -16,7 +16,7 @@ function Navbar(props) { const navigate = useNavigate(); const location = useLocation(); - const { currentUser } = useAuth(); + const { currentUser, userLoggedIn, setUserLoggedIn } = useAuth(); const [isScrolled, setIsScrolled] = useState(false); // State to keep track of whether page has been scrolled // eslint-disable-next-line const [isOpen, setIsOpen] = useState(false); @@ -82,6 +82,7 @@ function Navbar(props) { try { doSignOut(); localStorage.removeItem("token"); + setUserLoggedIn(false) navigate("/login"); } catch (error) { console.error(error); @@ -237,7 +238,7 @@ function Navbar(props) { {/* Right Links */}
- {localStorage.getItem("token") ? ( + {localStorage.getItem("token") || userLoggedIn ? ( <>
    diff --git a/client/src/contexts/authContext/index.jsx b/client/src/contexts/authContext/index.jsx index ecc4d83..6727e29 100644 --- a/client/src/contexts/authContext/index.jsx +++ b/client/src/contexts/authContext/index.jsx @@ -52,7 +52,8 @@ export function AuthProvider({ children }) { isEmailUser, isGoogleUser, currentUser, - setCurrentUser + setCurrentUser, + setUserLoggedIn }; return ( diff --git a/client/src/firebase/auth.js b/client/src/firebase/auth.js index 63cf30b..9c02876 100644 --- a/client/src/firebase/auth.js +++ b/client/src/firebase/auth.js @@ -1,4 +1,4 @@ -import { auth } from "./firebase"; +import { auth } from "./firebase.js"; import { createUserWithEmailAndPassword, signInWithEmailAndPassword, diff --git a/server/.env.sample b/server/.env.sample index 576e136..c619c7e 100644 --- a/server/.env.sample +++ b/server/.env.sample @@ -22,4 +22,6 @@ EMAIL_USER = "" EMAIL_PASS = "" GOOGLE_CLIENT_ID = "" -JWT_SECRET = "" \ No newline at end of file +JWT_SECRET = "" +TWILIO_ACCOUNT_SID="" +TWILIO_AUTH_TOKEN="" \ No newline at end of file diff --git a/server/Controllers/auth.js b/server/Controllers/auth.js index 1e084cb..87b9cf1 100644 --- a/server/Controllers/auth.js +++ b/server/Controllers/auth.js @@ -4,6 +4,8 @@ const nodemailer = require("nodemailer"); const crypto = require("crypto"); require('dotenv').config(); // Load environment variables from .env file +const client = require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN); + // Signup route const createUser = async (req, res) => { const VITE_CLIENT_PORT = process.env.VITE_CLIENT_PORT || "https://bitbox-in.netlify.app"; @@ -16,9 +18,9 @@ const createUser = async (req, res) => { const image = `https://api.dicebear.com/5.x/initials/svg?seed=${name}`; // Create a new user (save in your database) - const user = new User({ image: image, name, email, password: hashedPassword, verified: false }); + const user = new User({ imageUrl: image, name, email, password: hashedPassword, verified: false }); await user.save(); - + const verificationToken = crypto.randomBytes(32).toString("hex"); user.verificationToken = verificationToken; await user.save(); @@ -52,6 +54,7 @@ const createUser = async (req, res) => { } }); } catch (error) { + console.log(error); res.status(500).json({ success: false, message: 'An error occurred during signup' }); } }; @@ -174,9 +177,48 @@ const forgetpassword = async (req, res) => { } }; +const sendOtp = async (req, res)=> { + const { number } = req.body; + + const otp = Math.floor(100000 + Math.random() * 900000).toString(); + + const result = await client.messages.create({ + body: `Yout OTP is ${otp}`, + messagingServiceSid: "MG6cd72a2fcb56205180ce4878359484cc", + to: "+91" + number + }) + + res.cookie('otp', otp, { + maxAge: 24 * 60 * 60 * 1000, + httpOnly: true, + secure: true, + sameSite: 'None', + }); + + return res.status(200).json({success: true, message: "OTP sent successfully"}) +} + +const verifyOtp = async (req, res)=>{ + const {otp} = req.body; + + console.log(req.cookies); + + const correctOtp = await req.cookies.otp + + if(correctOtp != otp){ + return res.status(400).json({success: false, message: "Incorrect OTP"}) + } + + res.clearCookie('otp'); + + return res.status(200).json({success: true, message: "OTP verified successfully"}) +} + module.exports = { forgetpassword, createUser, verifyToken, ResetPasswordByEmail, + sendOtp, + verifyOtp }; diff --git a/server/index.js b/server/index.js index 45a3872..ac2d2ed 100644 --- a/server/index.js +++ b/server/index.js @@ -4,12 +4,14 @@ const connectToMongo = require("./db"); const cors = require("cors"); const helmet = require("helmet"); const Avatar = require("./Models/Avatar"); +const cookieParser = require('cookie-parser'); require("dotenv").config(); // Load environment variables from .env file // Connect to MongoDB connectToMongo(); const app = express(); +app.use(cookieParser()); const httpServer = require("http").createServer(app); const io = new Server(httpServer, { cors: { @@ -33,6 +35,7 @@ app.use( cors({ origin: "*", // Update to specific origins in production methods: ["GET", "POST", "OPTIONS", "PUT"], + credentials: true, }) ); diff --git a/server/package-lock.json b/server/package-lock.json index 8634f66..6d583cf 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "bcrypt": "^5.1.1", "bcryptjs": "^2.4.3", + "cookie-parser": "^1.4.7", "cors": "^2.8.5", "dotenv": "^16.4.4", "express": "^4.18.2", @@ -26,7 +27,8 @@ "multer": "^1.4.5-lts.1", "nodemailer": "^6.9.15", "opensource-backend": "file:", - "socket.io": "^4.7.5" + "socket.io": "^4.7.5", + "twilio": "^5.3.5" }, "devDependencies": { "nodemon": "^3.1.7" @@ -902,6 +904,23 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1161,6 +1180,18 @@ "color-support": "bin.js" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1218,6 +1249,28 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -1243,6 +1296,12 @@ "node": ">= 0.10" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1269,6 +1328,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -1607,6 +1675,40 @@ "@firebase/vertexai-preview": "0.0.4" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2987,6 +3089,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -3127,6 +3235,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/scmp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==", + "license": "BSD-3-Clause" + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -3528,6 +3642,24 @@ "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "license": "0BSD" }, + "node_modules/twilio": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-5.3.5.tgz", + "integrity": "sha512-f/sA1Yd6TyIzfcq0u4QDGU+93afwswsJB+rf3T08tvBAMobBDVR3DfGREwJr5jp8xUic0qWa7GbJidk16NA4bg==", + "license": "MIT", + "dependencies": { + "axios": "^1.7.4", + "dayjs": "^1.11.9", + "https-proxy-agent": "^5.0.0", + "jsonwebtoken": "^9.0.2", + "qs": "^6.9.4", + "scmp": "^2.1.0", + "xmlbuilder": "^13.0.2" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -3716,6 +3848,15 @@ } } }, + "node_modules/xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/server/package.json b/server/package.json index 7f35ab6..0bf0e4e 100644 --- a/server/package.json +++ b/server/package.json @@ -19,6 +19,7 @@ "dependencies": { "bcrypt": "^5.1.1", "bcryptjs": "^2.4.3", + "cookie-parser": "^1.4.7", "cors": "^2.8.5", "dotenv": "^16.4.4", "express": "^4.18.2", @@ -34,7 +35,8 @@ "multer": "^1.4.5-lts.1", "nodemailer": "^6.9.15", "opensource-backend": "file:", - "socket.io": "^4.7.5" + "socket.io": "^4.7.5", + "twilio": "^5.3.5" }, "devDependencies": { "nodemon": "^3.1.7" diff --git a/server/routes/auth.js b/server/routes/auth.js index 7cd79fc..198118d 100644 --- a/server/routes/auth.js +++ b/server/routes/auth.js @@ -15,6 +15,8 @@ const { verifyToken, createUser, ResetPasswordByEmail, + verifyOtp, + sendOtp } = require("../Controllers/auth"); // Configure Firebase OAuth2Client @@ -161,5 +163,7 @@ router.post("/forget", forgetpassword); router.post("/createUser", createUser); router.post("/verify/:token", verifyToken); router.post("/ResetByEmail", ResetPasswordByEmail); +router.post("/sendotp", sendOtp); +router.post("/verifyotp", verifyOtp); module.exports = router;