Files
me-api/api/auth-router.ts
Superuser 40d3a66055 init: me-api 个人简历后台
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 20:10:56 +08:00

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 };
}),
});