ff98547dbb
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
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 };
|
|
}),
|
|
});
|