diff --git a/frontend-next/src/app/api/login/route.js b/frontend-next/src/app/api/login/route.js deleted file mode 100644 index 0c8d43c..0000000 --- a/frontend-next/src/app/api/login/route.js +++ /dev/null @@ -1,94 +0,0 @@ -import { cookies } from "next/headers"; -import { NextResponse } from "next/server"; -// Firebase Imports -import { auth } from "firebase-admin"; -import { signInWithEmailAndPassword } from "firebase/auth"; -// Lib Imports -import { auth as authConfig, database} from "../firebase-config"; -import { customInitApp } from "../firebase-admin"; -import { ref, get as firebaseGet } from "firebase/database"; - -// Needs to "init" on each call to the API -customInitApp(); - -// Login with Email/Password -async function handleEmailAndPassword(email, password) { - try { - var userCredential = await signInWithEmailAndPassword(authConfig,email,password); - if (userCredential.user.accessToken) { - var token = await auth().verifyIdToken(userCredential.user.accessToken); - var expiresIn = 20 * 60 * 1000; // 20 minutes - var sessionCookie = await auth().createSessionCookie(userCredential.user.accessToken, {expiresIn,}); - if (token) { - var user = await firebaseGet(ref(database, `users/${userCredential.user.uid}`)); - if (!user.exists()) { - var userOptions = { - name: "user", - value: JSON.stringify({defined: false, uid: userCredential.user.uid}), - maxAge: expiresIn, // 20 mins - httpOnly: true, - secure: true, - }; - } else { - var userData = user.val() - userData.uid = userCredential.user.uid - userData.defined = true - var userOptions = { - name: "user", - value: JSON.stringify(userData), - maxAge: expiresIn, // 20 mins - httpOnly: true, - secure: true, - }; - } - cookies().set(userOptions); - var options = { - name: "session", - value: sessionCookie, - maxAge: expiresIn, // 20 mins - httpOnly: true, - secure: true, - }; - cookies().set(options); - cookies().set({ - name: "uid", - value: userCredential.user.uid, - maxAge: expiresIn, // 20 mins - httpOnly: true, - secure: true, - }); - return NextResponse.json({ options }, { status: 200 }); - } - } - } catch (error) { - return NextResponse.json({ error: error.code }, { status: 401 }); - } -} - -// Handles POST requests (login requests) -export async function POST(req, res) { - try { - var { email, password } = await req?.json() - return await handleEmailAndPassword(email, password); // need session token - } catch (error) { - return NextResponse.json({ error: "Internal Server Error" },{ status: 500 }); - } -} - -// Handles GET requests (is session still valid requests) -export async function GET(req) { - var session = cookies().get("session")?.value || ""; - //Validate if the cookie exist in the request - if (!session) { - return NextResponse.json({ isLogged: false }, { status: 401 }); - } else { - // Validate session cookie - try { - var validation = await auth().verifySessionCookie(session, true); - return NextResponse.json({ isLogged: true, uid: validation.uid, email: validation.email }, { status: 200 }); - } catch (error) { - return NextResponse.json({ isLogged: false}, { status: 401 }); - } - - } -} \ No newline at end of file diff --git a/frontend-next/src/app/api/register/route.js b/frontend-next/src/app/api/register/route.js deleted file mode 100644 index 9bc7268..0000000 --- a/frontend-next/src/app/api/register/route.js +++ /dev/null @@ -1,42 +0,0 @@ -// Import necessary functions -import { createUserWithEmailAndPassword } from "firebase/auth"; -import { auth } from "../firebase-config"; -import { NextResponse } from "next/server"; - -// Function to register a new user using Firebase Authentication -export async function registerUser(email, password) { - try { - var userCredential = await createUserWithEmailAndPassword(auth,email,password); - // You can perform additional actions after successful registration, if needed. - return { success: true, userCredential }; - } catch (error) { - return { success: false, error: error.message }; - } -} - -// POST request handler -export async function POST(req, res) { - try { - // Extract email and password from the request body - var { email, password } = await req?.json(); - // Check if email and password are provided - if (!email || !password) { - return NextResponse.json( - { error: "Email and password are required." }, - { status: 400 } - ); - } - - // Register the user - try { - var userCredential = await createUserWithEmailAndPassword(auth,email,password); - return NextResponse.json({message: "Registration successful.",user: userCredential.user,}); - } catch { - return NextResponse.json({ error: registrationResult.error },{ status: 500 }); - } - - } catch (error) { - // Handle unexpected errors - return NextResponse.json({ error: "Internal Server Error" },{ status: 500 }); - } -} \ No newline at end of file diff --git a/frontend-next/src/app/api/signout/route.js b/frontend-next/src/app/api/signout/route.js index e107f50..576fe85 100644 --- a/frontend-next/src/app/api/signout/route.js +++ b/frontend-next/src/app/api/signout/route.js @@ -1,10 +1,13 @@ import { cookies } from "next/headers"; import { NextResponse } from "next/server"; +import {signOut} from "firebase/auth"; +import {auth} from "../firebase-config"; export async function GET(req) { cookies().delete('user') cookies().delete('session') cookies().delete('uid') + await signOut(auth) return NextResponse.redirect(new URL("/",req.url)) } \ No newline at end of file diff --git a/frontend-next/src/app/api/user/route.js b/frontend-next/src/app/api/user/route.js deleted file mode 100644 index 1efb9e2..0000000 --- a/frontend-next/src/app/api/user/route.js +++ /dev/null @@ -1,7 +0,0 @@ -import { NextResponse } from "next/server"; -import { cookies } from "next/headers"; - -export async function GET(req) { - var userData = cookies().get("user")?.value || false - return userData != false? NextResponse.json(JSON.parse(userData)): NextResponse.json({},{status: 203}) -} \ No newline at end of file diff --git a/frontend-next/src/app/app/page.js b/frontend-next/src/app/app/page.js index 585117c..a5081cc 100644 --- a/frontend-next/src/app/app/page.js +++ b/frontend-next/src/app/app/page.js @@ -1,10 +1,12 @@ "use client"; // System Imports import { useState, useEffect } from "react"; -import { database } from "../api/firebase-config"; -import { ref, onValue, set, remove } from "firebase/database"; +import { auth, database } from "../api/firebase-config"; +import { ref, onValue, set, remove, get } from "firebase/database"; import { useBeforeunload } from "react-beforeunload"; +import {useRouter} from "next/router"; import {Marker} from "pigeon-maps"; +import {onAuthStateChanged, signOut} from "firebase/auth" // Refactored Component Imports // Data Structure Imports @@ -41,45 +43,61 @@ function Home() { const [chatroomUsers, setChatroomUsers] = useState(null); // holds all chatroom users const [chatroomUsersLoading, setChatroomUsersLoading] = useState(true); const [markers, setMarkers] = useState([]); + const [isAuthenticated, setAuth] = useState(false) + const [user, setUser] = useState(null) + + // Authentication + useEffect(() => { + onAuthStateChanged(auth, (user) => { + if (user) { + get(ref(database, `users/${user.uid}`)) + .then((user) => { + setUser(user.val()) + setAuth(true) + }) + } else { + setAuth(false) + } + }) + }, []) + // Grabs user data, saves to user, then lists the users saved rooms useEffect(() => { - fetch("/api/user") - .then((res) => res.json()) - .then((user) => { - onValue(ref(database, "/users/" + user.uid + "/rooms"), (snapshot) => { - setRoomLoading(true); - var rooms = snapshot.val(); - setMyRoomsObj(rooms); - var roomArr = []; - var markerArr = markers; - for (var room in rooms) { - var newRoom = ( - - ); - markerArr.push( - - ); - roomArr.push(newRoom); - } - setMarkers(markerArr); - setRoomData(roomArr); - setRoomLoading(false); - }); - }); - },[]); + if (user) { + onValue(ref(database, "/users/" + user.uid + "/rooms"), (snapshot) => { + setRoomLoading(true); + var rooms = snapshot.val(); + setMyRoomsObj(rooms); + var roomArr = []; + var markerArr = markers; + for (var room in rooms) { + var newRoom = ( + + ); + markerArr.push( + + ); + roomArr.push(newRoom); + } + setMarkers(markerArr); + setRoomData(roomArr); + setRoomLoading(false); + }); + } + },[user]); // Grabs the user location useEffect(() => { - if ("geolocation" in navigator) { + if ("geolocation" in navigator && user) { // Retrieve latitude & longitude coordinates from `navigator.geolocation` Web API navigator.geolocation.getCurrentPosition(({ coords }) => { @@ -113,7 +131,7 @@ function Home() { }); }); } - },[]); + },[user]); // Dont Double Send Leaving Message @@ -132,9 +150,6 @@ function Home() { // Selects chat room function selectChatRoom(roomObj) { - fetch("/api/user") - .then((res) => res.json()) - .then((user) => { // Path of chatroom var path = roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp; @@ -192,14 +207,10 @@ function Home() { } }); setMainTab("chat"); - }); } // Fires to tell other uses that you are leaving the room useBeforeunload(() => { - fetch("/api/user") - .then((res) => res.json()) - .then((user) => { if (chatRoomObj && mainTab == "chat") { var payload = { body: "left", @@ -229,41 +240,44 @@ function Home() { chatRoomObj.name + "-" + chatRoomObj.timestamp - }/users/online/${user.uid}` + }/users/online/${userID}` ) ); } - }); }); return ( -
- {/* Left Side of Page */} -
- {/* Header */} -
- {/* Main Page Section */} -
- {mainTab == "home" && !loadingLoc && ( - +
+ {isAuthenticated && ( +
+ {/* Left Side of Page */} +
+ {/* Header */} +
+ {/* Main Page Section */} +
+ {mainTab == "home" && !loadingLoc && ( + + )} + {mainTab == "home" && loadingLoc && ( + + )} + {mainTab == "chat" && } +
+
+ {/* Sidebar (Right Side of Page) */} + {mainTab == "home" && ( + )} - {mainTab == "home" && loadingLoc && ( - + {mainTab == "chat" && ( + + )} + {mainTab == "profile" && ( + )} - {mainTab == "chat" && }
-
- {/* Sidebar (Right Side of Page) */} - {mainTab == "home" && ( - )} - {mainTab == "chat" && ( - - )} - {mainTab == "profile" && ( - - )} -
+
); } diff --git a/frontend-next/src/app/login/page.js b/frontend-next/src/app/login/page.js index 173b9b4..713154a 100644 --- a/frontend-next/src/app/login/page.js +++ b/frontend-next/src/app/login/page.js @@ -8,14 +8,17 @@ import {auth, database} from "../api/firebase-config"; import { setPersistence, signInWithEmailAndPassword, browserSessionPersistence } from "firebase/auth"; import { ref, get } from "firebase/database"; -function authenticate({data}) { +async function authenticate(data) { setPersistence(auth, browserSessionPersistence) .then(async () => { - var userCredential = await signInWithEmailAndPassword(auth,data.email,data.password); - if (userCredential.user.accessToken) { - var token = userCredential.user.accessToken - console.log(token) - } + signInWithEmailAndPassword(auth,data.email,data.password) + .then((userCredential) => { + if (userCredential.user) { + return true + } else { + return false + } + }) }) } @@ -23,6 +26,14 @@ function Login() { var router = useRouter(); //var { register, handleSubmit } = useForm(); var { register, control, setError, formState: { errors, isSubmitting, isSubmitted } } = useForm() + + async function authenticationPush({data}) { + if (authenticate(data)) { + console.log("Fire") + router.push("/"); + } + } + return (
@@ -34,10 +45,7 @@ function Login() {

Login

{(errors.email && errors.password) &&
Invalid Email or Password.
} -
{ - router.push("/app"); - }} + { const formError = { type: "server", message: "Username or Password Incorrect" } // set same error in both: diff --git a/frontend-next/src/app/page.js b/frontend-next/src/app/page.js index b0a7afc..10a8bf5 100644 --- a/frontend-next/src/app/page.js +++ b/frontend-next/src/app/page.js @@ -1,23 +1,28 @@ "use client" import { useState, useEffect } from 'react' -import { database } from "./api/firebase-config"; +import { auth, database } from "./api/firebase-config"; import { ref, get} from "firebase/database"; +import {onAuthStateChanged} from "firebase/auth" function Home() { - const [statusCode, setData] = useState(null) - const [isLoading, setLoading] = useState(true) const [isLoadingLoc, setLoadingLoc] = useState(true) const [roomCount, setRoomCount] = useState(null) - useEffect(() => { - fetch('/api/user') - .then((res) => res.status) - .then((status) => { - setData(status) - setLoading(false) - }) - }, []) + const [isAuthenticated, setAuth] = useState(false) + const [userID, setUserID] = useState(null) + + // Authentication + useEffect(() => { + onAuthStateChanged(auth, (user) => { + if (user) { + setUserID(user.uid) + setAuth(true) + } else { + setAuth(false) + } + }) + }, []) useEffect(() => { if('geolocation' in navigator) { @@ -49,13 +54,13 @@ function Home() { Chat with friends!
- {(statusCode == 203 || isLoading) && + {(!isAuthenticated) && } - {statusCode == 200 && } + {isAuthenticated && } {(!isLoadingLoc && roomCount == 1) &&
Join others in {roomCount} room near you!
} {(!isLoadingLoc && roomCount != 1 && roomCount != 0) &&
Join others in {roomCount} rooms near you!
} {(isLoadingLoc || (roomCount == 0 && !isLoadingLoc)) &&
Start the conversation today!
} diff --git a/frontend-next/src/app/register/page.js b/frontend-next/src/app/register/page.js index 1a000da..c9fa086 100644 --- a/frontend-next/src/app/register/page.js +++ b/frontend-next/src/app/register/page.js @@ -4,21 +4,33 @@ import { useForm, Form } from "react-hook-form"; import "../globals.css" import { useState } from "react"; +import { createUserWithEmailAndPassword } from "firebase/auth"; +import {auth} from "../api/firebase-config"; + +async function Signup(data) { + var userCredential = await createUserWithEmailAndPassword(auth,data.email,data.password); + if (userCredential.user) { + return true + } else { + return false + } +} function Register() { - var { register, control, handleSubmit, formState: { errors } } = useForm() var router = useRouter(); + var { register, control, handleSubmit, formState: { errors } } = useForm() var emailRegex = /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/ var [passwordMismatch, setPasswordMismatch] = useState(false); - const passwordMatch = (data) => { return data.password === data.passwordCheck; }; - - const onSubmit = (data) => { + + function onSubmit({data}) { if (passwordMatch(data)) { setPasswordMismatch(false); - router.push("/success"); + if (Signup(data)) { + router.push("/app"); + } } else{ setPasswordMismatch(true); @@ -36,11 +48,7 @@ function Register() {

Register

- { - router.push("/app"); - }} - action="/api/register" + diff --git a/frontend-next/src/components/app/header.js b/frontend-next/src/components/app/header.js index 6411d7f..916afe6 100644 --- a/frontend-next/src/components/app/header.js +++ b/frontend-next/src/components/app/header.js @@ -1,11 +1,9 @@ -import { database } from "../../app/api/firebase-config"; +import { auth, database } from "../../app/api/firebase-config"; import { ref, set, remove } from "firebase/database"; +import {signOut} from "firebase/auth"; // Closes chat room - function closeChatRoom(roomObj, setChatRoomObj, setMainTab) { - fetch("/api/user") - .then((res) => res.json()) - .then((user) => { + function closeChatRoom(roomObj, setChatRoomObj, setMainTab, user) { var path = roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp; var payload = { body: "left", @@ -23,14 +21,10 @@ import { ref, set, remove } from "firebase/database"; remove(ref(database, `/rooms/${path}/users/online/${user.uid}`)); setChatRoomObj(null); setMainTab("home"); - }); } // Adds room to myRooms - function addToMyRooms(chatRoomObj, setIsMyRoom) { - fetch("/api/user") - .then((res) => res.json()) - .then((user) => { + function addToMyRooms(chatRoomObj, setIsMyRoom, user) { set( ref( database, @@ -52,15 +46,11 @@ import { ref, set, remove } from "firebase/database"; "-" + chatRoomObj.timestamp; set(ref(database, `/rooms/${path}/users/all/${user.uid}`), user); - }); setIsMyRoom(true); } // Deletes saved room from myRooms - function removeFromMyRooms(chatRoomObj, setIsMyRoom) { - fetch("/api/user") - .then((res) => res.json()) - .then((user) => { + function removeFromMyRooms(chatRoomObj, setIsMyRoom, user) { var path = chatRoomObj.path + "/" + @@ -74,11 +64,10 @@ import { ref, set, remove } from "firebase/database"; ) ); remove(ref(database, `/rooms/${path}/users/all/${user.uid}`)); - }); setIsMyRoom(false); } -export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainTab, setIsMyRoom}) { +export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainTab, setIsMyRoom, user}) { return (
@@ -93,7 +82,7 @@ export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainT {mainTab == "chat" && isMyRoom == false && ( { - addToMyRooms(chatRoomObj, setIsMyRoom); + addToMyRooms(chatRoomObj, setIsMyRoom, user); }} className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5" > @@ -103,7 +92,7 @@ export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainT {mainTab == "chat" && isMyRoom == true && ( { - removeFromMyRooms(chatRoomObj, setIsMyRoom); + removeFromMyRooms(chatRoomObj, setIsMyRoom, user); }} className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5" > @@ -113,7 +102,7 @@ export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainT {mainTab == "chat" && ( { - closeChatRoom(chatRoomObj, setChatRoomObj, setMainTab); + closeChatRoom(chatRoomObj, setChatRoomObj, setMainTab, user); }} className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5" > @@ -121,7 +110,7 @@ export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainT )} Sign Out diff --git a/frontend-next/src/components/app/main_tab/chat.js b/frontend-next/src/components/app/main_tab/chat.js index b3011d9..62cc531 100644 --- a/frontend-next/src/components/app/main_tab/chat.js +++ b/frontend-next/src/components/app/main_tab/chat.js @@ -6,7 +6,7 @@ import { database } from "../../../app/api/firebase-config"; // Chatroom Module for Primary Tab -export function MainTabChatRoom({ roomObj }) { +export function MainTabChatRoom({ roomObj, user }) { var { register, control, reset, handleSubmit } = useForm(); const [chats, setData] = useState(null); const [isLoading, setLoading] = useState(true); @@ -48,9 +48,6 @@ export function MainTabChatRoom({ roomObj }) { function sendMessage(data) { reset(); - fetch("/api/user") - .then((res) => res.json()) - .then((user) => { var payload = { body: data.message, user: user.username, @@ -66,7 +63,6 @@ export function MainTabChatRoom({ roomObj }) { ), payload ); - }); } if (isLoading) return
Loading
; diff --git a/frontend-next/src/components/app/main_tab/home.js b/frontend-next/src/components/app/main_tab/home.js index eb1b65d..c492063 100644 --- a/frontend-next/src/components/app/main_tab/home.js +++ b/frontend-next/src/components/app/main_tab/home.js @@ -1,27 +1,11 @@ -import { useState, useEffect } from "react"; - - import {Geo} from "../datatypes" // Module for Welcome Message on main tab landing page -function WelcomeMessage() { - const [data, setData] = useState(null); - const [isLoading, setLoading] = useState(true); - useEffect(() => { - fetch("/api/user") - .then((res) => res.json()) - .then((data) => { - setData(data); - setLoading(false); - }); - }, []); - if (isLoading) return
; - if (!data) return
; - +function WelcomeMessage({user}) { return (
- Welcome, {data.firstName} {data.lastName} ({data.username}) + Welcome, {user.firstName} {user.lastName} ({user.username})
Lets see what's happening in your area.
@@ -29,10 +13,10 @@ function WelcomeMessage() { } // Primary App Landing Page -export function MainTabHome({ loc, markers }) { +export function MainTabHome({ loc, markers, user }) { return ( <> - +