const express = require("express"); const jwt = require("jsonwebtoken"); const { OAuth2Client } = require("google-auth-library"); const { User } = require("../models"); // Import from models/index.js to get models with associations const router = express.Router(); const googleClient = new OAuth2Client(process.env.GOOGLE_CLIENT_ID); router.post("/register", async (req, res) => { try { const { username, email, password, firstName, lastName, phone } = req.body; const existingUser = await User.findOne({ where: { [require("sequelize").Op.or]: [{ email }, { username }], }, }); if (existingUser) { return res.status(400).json({ error: "User already exists" }); } const user = await User.create({ username, email, password, firstName, lastName, phone, }); const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: "7d", }); res.status(201).json({ user: { id: user.id, username: user.username, email: user.email, firstName: user.firstName, lastName: user.lastName, }, token, }); } catch (error) { res.status(500).json({ error: error.message }); } }); router.post("/login", async (req, res) => { try { const { email, password } = req.body; const user = await User.findOne({ where: { email } }); if (!user || !(await user.comparePassword(password))) { return res.status(401).json({ error: "Invalid credentials" }); } const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: "7d", }); res.json({ user: { id: user.id, username: user.username, email: user.email, firstName: user.firstName, lastName: user.lastName, }, token, }); } catch (error) { res.status(500).json({ error: error.message }); } }); router.post("/google", async (req, res) => { try { const { idToken } = req.body; if (!idToken) { return res.status(400).json({ error: "ID token is required" }); } // Verify the Google ID token const ticket = await googleClient.verifyIdToken({ idToken, audience: process.env.GOOGLE_CLIENT_ID, }); const payload = ticket.getPayload(); const { sub: googleId, email, given_name: firstName, family_name: lastName, picture, } = payload; if (!email || !firstName || !lastName) { return res .status(400) .json({ error: "Required user information not provided by Google" }); } // Check if user exists by Google ID first let user = await User.findOne({ where: { providerId: googleId, authProvider: "google" }, }); if (!user) { // Check if user exists with same email but different auth provider const existingUser = await User.findOne({ where: { email } }); if (existingUser) { return res.status(409).json({ error: "An account with this email already exists. Please use email/password login.", }); } // Create new user user = await User.create({ email, firstName, lastName, authProvider: "google", providerId: googleId, profileImage: picture, username: email.split("@")[0] + "_" + googleId.slice(-6), // Generate unique username }); } // Generate JWT token const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: "7d", }); res.json({ user: { id: user.id, username: user.username, email: user.email, firstName: user.firstName, lastName: user.lastName, profileImage: user.profileImage, }, token, }); } catch (error) { if (error.message && error.message.includes("Token used too late")) { return res .status(401) .json({ error: "Google token has expired. Please try again." }); } if (error.message && error.message.includes("Invalid token")) { return res .status(401) .json({ error: "Invalid Google token. Please try again." }); } if (error.message && error.message.includes("Wrong number of segments")) { return res .status(400) .json({ error: "Malformed Google token. Please try again." }); } res .status(500) .json({ error: "Failed to authenticate with Google: " + error.message }); } }); module.exports = router;