64 lines
2.4 KiB
TypeScript
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.rows.length > 0)
|
|
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)]);
|
|
}
|