import { z } from "zod"; import * as cookie from "cookie"; import { createRouter, publicQuery, authedQuery } from "./middleware"; import { getSessionCookieOptions } from "./lib/cookies"; import { signSessionToken } from "./lib/session"; import { env } from "./lib/env"; import { findUserByUnionId, upsertUser } from "./queries/users"; import { Session } from "@contracts/constants"; export const authRouter = createRouter({ login: publicQuery .input(z.object({ username: z.string(), password: z.string() })) .mutation(async ({ input, ctx }) => { if ( input.username !== env.adminUsername || input.password !== env.adminPassword ) { throw new Error("Invalid username or password"); } await upsertUser({ unionId: input.username, name: input.username, role: "admin" as const, lastSignInAt: new Date(), }); const user = await findUserByUnionId(input.username); if (!user) { throw new Error("Failed to create user"); } const token = await signSessionToken({ userId: user.id }); const cookieOpts = getSessionCookieOptions(ctx.req.headers); ctx.resHeaders.append( "set-cookie", cookie.serialize(Session.cookieName, token, { httpOnly: cookieOpts.httpOnly, path: cookieOpts.path, sameSite: cookieOpts.sameSite?.toLowerCase() as "lax" | "none", secure: cookieOpts.secure, maxAge: Session.maxAgeMs / 1000, }), ); return user; }), me: authedQuery.query((opts) => opts.ctx.user), logout: authedQuery.mutation(async ({ ctx }) => { const opts = getSessionCookieOptions(ctx.req.headers); ctx.resHeaders.append( "set-cookie", cookie.serialize(Session.cookieName, "", { httpOnly: opts.httpOnly, path: opts.path, sameSite: opts.sameSite?.toLowerCase() as "lax" | "none", secure: opts.secure, maxAge: 0, }), ); return { success: true }; }), });