Import source: backend/src/lib/auth

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:09:16 +03:30
parent e33adbc2c7
commit 3c133e7954
+62
View File
@@ -0,0 +1,62 @@
import type { FastifyInstance, FastifyRequest } from "fastify";
import type { SessionContext } from "./serializers.js";
import { forbidden, permissionDenied } from "./envelope.js";
export function parseCookies(header: string | undefined) {
const cookies: Record<string, string> = {};
if (!header) return cookies;
for (const part of header.split(";")) {
const [rawKey, ...rawValue] = part.trim().split("=");
if (!rawKey) continue;
cookies[rawKey] = decodeURIComponent(rawValue.join("="));
}
return cookies;
}
export function sessionCookie(request: FastifyRequest) {
return parseCookies(request.headers.cookie).session_id;
}
export async function requireSession(app: FastifyInstance, request: FastifyRequest) {
const sessionId = sessionCookie(request);
if (!sessionId) throw permissionDenied();
const session = await app.prisma.session.findUnique({
where: { id: sessionId },
include: {
user: {
include: {
permissions: true,
accounts: true,
},
},
},
});
if (!session || session.expiresAt <= new Date()) {
if (session) {
await app.prisma.session.delete({ where: { id: session.id } }).catch(() => undefined);
}
throw permissionDenied();
}
return session as SessionContext;
}
export async function requireRole(
app: FastifyInstance,
request: FastifyRequest,
roles: string[],
) {
const session = await requireSession(app, request);
if (!roles.includes(session.user.role)) {
throw forbidden(`Role ${session.user.role} is not authorized for this operation.`);
}
return session;
}
export function accountIdFor(session: SessionContext) {
return session.user.accounts[0]?.accountId ?? "acct-main";
}