46 lines
1.4 KiB
TypeScript
46 lines
1.4 KiB
TypeScript
import { db } from "../db.ts";
|
|
import { TOKEN_TTL_DAYS } from "../auth.ts";
|
|
|
|
export const handleLogin = async (req: Request): Promise<Response> => {
|
|
if (req.method !== "POST") {
|
|
return Response.json({ error: "Method not allowed" }, { status: 405 });
|
|
}
|
|
|
|
let body: unknown;
|
|
try {
|
|
body = await req.json();
|
|
} catch {
|
|
return Response.json({ error: "Invalid JSON" }, { status: 400 });
|
|
}
|
|
|
|
if (!body || typeof body !== "object") {
|
|
return Response.json({ error: "Body must be a JSON object" }, { status: 400 });
|
|
}
|
|
|
|
const { username, password } = body as { username?: string; password?: string };
|
|
if (!username || !password) {
|
|
return Response.json({ error: "username and password required" }, { status: 400 });
|
|
}
|
|
|
|
const [user] = await db`
|
|
SELECT id, password_hash FROM users WHERE username = ${username}
|
|
`;
|
|
|
|
if (!user || !await Bun.password.verify(password, user.password_hash as string)) {
|
|
return Response.json({ error: "Invalid credentials" }, { status: 401 });
|
|
}
|
|
|
|
const token = crypto.randomUUID();
|
|
const expiresAt = new Date(Date.now() + TOKEN_TTL_DAYS * 86_400_000)
|
|
.toISOString()
|
|
.replace("T", " ")
|
|
.slice(0, 19);
|
|
|
|
await db`
|
|
INSERT INTO auth_tokens (user_id, token, expires_at)
|
|
VALUES (${user.id}, ${token}, ${expiresAt})
|
|
`;
|
|
|
|
return Response.json({ token });
|
|
};
|