fiddy/apps/web/lib/server/auth-service.ts
2026-02-11 23:45:15 -08:00

64 lines
2.4 KiB
TypeScript

if (process.env.NODE_ENV !== "test")
require("server-only");
import getPool from "@/lib/server/db";
import { createSession, getSessionTtlMs, hashPassword, hashToken, verifyPassword } from "@/lib/server/auth";
import { apiError } from "@/lib/server/errors";
export async function registerUser(input: { email: string; password: string; displayName?: string }) {
const pool = getPool();
const email = input.email.trim().toLowerCase();
const existing = await pool.query("select id from users where email=$1", [email]);
if (existing.rowCount)
apiError("EMAIL_EXISTS", { email });
const passwordHash = await hashPassword(input.password);
let rows;
try {
const result = await pool.query(
"insert into users(email, display_name, password_hash) values($1,$2,$3) returning id, email, display_name",
[email, input.displayName || null, passwordHash]
);
rows = result.rows;
} catch (error) {
if (typeof error === "object" && error && "code" in error && error.code === "23505")
apiError("EMAIL_EXISTS", { email });
throw error;
}
const user = rows[0];
const session = await createSession(user.id);
return {
user: { id: user.id, email: user.email, displayName: user.display_name },
session
};
}
export async function loginUser(input: { email: string; password: string; remember: boolean }) {
const pool = getPool();
const email = input.email.trim().toLowerCase();
const { rows } = await pool.query(
"select id, email, display_name, password_hash from users where email=$1",
[email]
);
const user = rows[0];
if (!user)
apiError("INVALID_CREDENTIALS", { email });
const ok = await verifyPassword(input.password, user.password_hash);
if (!ok)
apiError("INVALID_CREDENTIALS", { email });
const shortTtlMs = 24 * 60 * 60 * 1000;
const session = await createSession(user.id, input.remember ? undefined : { ttlMs: shortTtlMs });
const ttlMs = input.remember ? getSessionTtlMs() : shortTtlMs;
return {
user: { id: user.id, email: user.email, displayName: user.display_name },
session: { ...session, ttlMs }
};
}
export async function logoutUser(token: string) {
const pool = getPool();
await pool.query("delete from sessions where token_hash=$1", [hashToken(token)]);
}