import config, { IS_PROD } from "@stealth-developers/config"; import db, { getSession, getUser, sessions, upsertUser } from "@stealth-developers/db"; import { RESTGetAPICurrentUserResult, type RESTPostOAuth2AccessTokenResult, RouteBases, Routes, } from "discord-api-types/v10"; import { Elysia, t } from "elysia"; import { type OAuth2ErrorResponse, isError, isOAuth2Error, makeRequest } from "./discord"; const CLIENT_ID = config.discord.app_id; const CLIENT_SECRET = config.discord.client_secret; const HOST = IS_PROD ? "https://tickets.vt3e.cat" : "http://127.0.0.1:3000"; const REDIRECT_URI = `${HOST}/auth/callback`; const FRONTEND_URL = IS_PROD ? HOST : "http://127.0.0.1:5173"; const authPlugin = new Elysia({ name: "auth" }) .guard({ as: "global", cookie: t.Cookie({ session_id: t.Optional(t.String()), }), }) .resolve({ as: "global" }, async ({ cookie: { session_id } }) => { const sessionId = session_id.value as string | undefined; if (!sessionId) return { session: null }; const session = await getSession(sessionId); if (!session || session.expiresAt < new Date()) return { session: null }; return { session }; }); const app = new Elysia() .use(authPlugin) .onError(({ error, set, request }) => { set.status = 500; console.error(request.url, error); if (error instanceof Error) return { message: error.message ?? "Internal Server Error" }; return { message: "Unknown Error" }; }) .group("/auth", (app) => app .get("/login", ({ redirect }) => { const redirectUri = `https://discord.com/oauth2/authorize?client_id=${CLIENT_ID}&response_type=code&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&scope=identify+guilds`; return redirect(redirectUri, 302); }) .get( "/callback", async ({ query: { code }, cookie: { session_id }, redirect }) => { const params = new URLSearchParams({ code, client_id: CLIENT_ID, client_secret: CLIENT_SECRET, grant_type: "authorization_code", redirect_uri: REDIRECT_URI, }); const tokenResponse = await fetch("https://discord.com/api/oauth2/token", { method: "POST", body: params, headers: { "Content-Type": "application/x-www-form-urlencoded" }, }); const tokenData = (await tokenResponse.json()) as | OAuth2ErrorResponse | RESTPostOAuth2AccessTokenResult; if (isOAuth2Error(tokenData)) throw new Error(tokenData.error_description ?? tokenData.error); const userData = await makeRequest( `${RouteBases.api}${Routes.user()}`, tokenData.access_token, ); if (isError(userData)) throw new Error(userData.message); const upsertedUser = await upsertUser({ avatar: userData.avatar, username: userData.username, displayName: userData.global_name, id: userData.id, }); const sessionId = crypto.randomUUID(); const expiresAt = new Date().getTime() + tokenData.expires_in * 1_000; await db.insert(sessions).values({ id: sessionId, userId: upsertedUser.id, accessToken: tokenData.access_token, refreshToken: tokenData.refresh_token, scope: tokenData.scope, tokenType: tokenData.token_type, createdAt: new Date(), expiresAt: new Date(expiresAt), }); session_id.set({ value: sessionId, httpOnly: true, path: "/", secure: IS_PROD, sameSite: "lax", expires: new Date(expiresAt), }); return redirect(FRONTEND_URL); }, { query: t.Object({ code: t.String(), }), }, ), ) .group("/api", (app) => app .resolve(({ session, status }) => { if (!session) return status(401, { message: "unauthorized" }); return { session }; }) .get("/me", async ({ session }) => { const user = await getUser(session.userId); return user; }), ) .listen(config.api.port); console.log(`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`);