diff --git a/package-lock.json b/package-lock.json index faec7c3..122d218 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@types/axios": "^0.9.36", "@types/date-fns": "^2.5.3", "@types/http-status-codes": "^1.2.0", + "@types/js-cookie": "^3.0.6", "axios": "^1.12.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -25,6 +26,7 @@ "date-fns": "^4.1.0", "emoji-picker-react": "^4.13.2", "http-status-codes": "^2.3.0", + "js-cookie": "^3.0.5", "lexical": "^0.34.0", "lucide-react": "^0.541.0", "next": "15.5.0", @@ -1990,6 +1992,12 @@ "http-status-codes": "*" } }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", + "license": "MIT" + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -2810,6 +2818,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/lexical": { "version": "0.34.0", "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.34.0.tgz", diff --git a/package.json b/package.json index c515807..c8216fb 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@types/axios": "^0.9.36", "@types/date-fns": "^2.5.3", "@types/http-status-codes": "^1.2.0", + "@types/js-cookie": "^3.0.6", "axios": "^1.12.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -28,6 +29,7 @@ "date-fns": "^4.1.0", "emoji-picker-react": "^4.13.2", "http-status-codes": "^2.3.0", + "js-cookie": "^3.0.5", "lexical": "^0.34.0", "lucide-react": "^0.541.0", "next": "15.5.0", diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts index 219739b..dbbfc46 100644 --- a/src/app/api/user/route.ts +++ b/src/app/api/user/route.ts @@ -33,14 +33,36 @@ export async function POST(req: NextRequest) { return NextResponse.json({ message: "ok", token, user_id: result.rows[0].id }); } +export async function GET(req: NextRequest) { + const url = new URL(req.url); + let query_id = url.searchParams.get("id"); + const token = url.searchParams.get("token"); + + if (!query_id && !token) + return NextResponse.json({ message: "Query arg should be token or id" }, { status: StatusCodes.BAD_REQUEST }); + else { + const id = query_id ? query_id : token ? CLIENT_AUTH_TOKENS[token] : null; + + if (!id) + return NextResponse.json({ message: "Invalid token" }, { status: StatusCodes.NOT_FOUND }); + + const user = await pool.query( + "SELECT id, username, email FROM users WHERE id = $1;", + [id] + ); + + return NextResponse.json({ message: "ok", ...user.rows[0] }); + } +} + export async function DELETE(req: NextRequest) { let { username } = await req.json(); - + await pool.query( "DELETE FROM users WHERE username = $1;", [username] ); - + return NextResponse.json({ message: "ok" }); } diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx new file mode 100644 index 0000000..95e3ac5 --- /dev/null +++ b/src/app/login/page.tsx @@ -0,0 +1,7 @@ +import { Input } from "@/components/ui/input"; + +export default function Login() { + return
+ +
+} \ No newline at end of file diff --git a/src/app/server/[id]/page.tsx b/src/app/server/[id]/page.tsx index b935e0b..a93b503 100644 --- a/src/app/server/[id]/page.tsx +++ b/src/app/server/[id]/page.tsx @@ -4,62 +4,69 @@ import { useEffect, useRef, useState } from "react"; import { useParams } from "next/navigation"; import MessageBox from "@/components/MessageBox"; import AppSidebar from "@/components/Sidebar"; -import { getUser } from '@/test/user'; -import { auth } from '@/test/auth'; import Message from "@/types/message"; +import getUser from "@/hooks/get-user"; +import Cookies from "js-cookie"; +import axios from "axios"; export default function Server() { - const { id } = useParams<{ id: string }>(); + const { id: ip } = useParams<{ id: string }>(); const wsRef = useRef(null); const [messages, setMessages] = useState([]); + const user = getUser(); useEffect(() => { - if (!id) return; + if (!ip || !user) return; - getUser().then(session_token => { - auth(session_token, id === 'localhost' ? '127.0.0.1' : id).then(server_auth => { - // Open the WebSocket connection - const ws = new WebSocket(`ws://${id}:7080`); - wsRef.current = ws; - - ws.onopen = () => { - console.log("Connected to WebSocket:", id); - ws.send(JSON.stringify({ - version: '0.0.1', - auth_token: server_auth, - last_message: 0 - })) - }; - - ws.onmessage = (m) => { - const data = JSON.parse(m.data); - console.log("Message received:", data); + async function auth() { + const server_auth = ((await axios.post('http://localhost:3000/api/auth', { + server_ip: ip === 'localhost' ? '127.0.0.1' : ip, + session_token: Cookies.get('token'), + })).data as any).token; - switch (data.type) { - case 'authenticated': - setMessages(data.params.messages); - - case 'message_create': - // setMessages([...messages, data.params]); - setMessages((prev) => [...prev, data.params]); - } - }; - - ws.onerror = (err) => { - console.error("WebSocket error:", err); - }; - - ws.onclose = () => { - console.log("WebSocket closed:", id); - }; - - // Cleanup on unmount or id change - return () => { - ws.close(); - }; - }); - }) - }, [id]); + // Open the WebSocket connection + const ws = new WebSocket(`ws://${ip}:7080`); + wsRef.current = ws; + + ws.onopen = () => { + console.log("Connected to WebSocket:", ip); + ws.send(JSON.stringify({ + version: '0.0.1', + auth_token: server_auth, + last_message: 0 + })) + }; + + ws.onmessage = (m) => { + const data = JSON.parse(m.data); + console.log("Message received:", data); + + switch (data.type) { + case 'authenticated': + setMessages(data.params.messages); + + case 'message_create': + // setMessages([...messages, data.params]); + setMessages((prev) => [...prev, data.params]); + } + }; + + ws.onerror = (err) => { + console.error("WebSocket error:", err); + }; + + ws.onclose = () => { + console.log("WebSocket closed:", ip); + }; + + // Cleanup on unmount or id change + return () => { + ws.close(); + }; + } + + auth(); + }, [ip]); return ( (); + + useEffect(() => { + async function fetchUser() { + const token = Cookies.get("token"); + + if (!token) { + redirect('/login') + } + + const res = (await axios.get('http://localhost:3000/api/user', { + params: { token } + })).data as User; + + setUser(res); + } + + fetchUser(); + }); + + return user; +} diff --git a/src/lib/api-wrapper/auth.ts b/src/lib/api-wrapper/auth.ts new file mode 100644 index 0000000..733b931 --- /dev/null +++ b/src/lib/api-wrapper/auth.ts @@ -0,0 +1,10 @@ +import axios from "axios"; + +export async function auth(session_token: string, server_ip: string) { + const res = (await axios.post('http://localhost:3000/api/auth', { + server_ip, + session_token, + })).data; + + return (res as any).token; +} diff --git a/src/test/user.js b/src/lib/api-wrapper/user.ts similarity index 100% rename from src/test/user.js rename to src/lib/api-wrapper/user.ts diff --git a/src/test/auth.js b/src/test/auth.js deleted file mode 100644 index b5539bc..0000000 --- a/src/test/auth.js +++ /dev/null @@ -1,19 +0,0 @@ -import axios from "axios"; -import { getUser } from "./user.js"; - -export async function auth(session_token, server_ip) { - const res = (await axios.post('http://localhost:3000/api/auth', { - server_ip, - session_token, - })).data; - - return res.token; -} - -// const session_token = await getUser(); - -// const token = await auth(session_token); - -// const output = (await axios.get('http://localhost:3000/api/auth?intents=server&token='+token)).data; - -// console.log(output); \ No newline at end of file