import type { FastifyReply, FastifyRequest } from 'fastify' import { getUserApps, getUserById, getUserPermissions, type UserRow, } from '@authportal/db' import type { AppId, MeResponse } from '@authportal/shared' import { APP_IDS, allPermissionKeys, normalizePermissionKeys } from '@authportal/shared' export type AuthUser = { id: string email: string name: string isAdmin: boolean apps: AppId[] permissions: string[] } declare module '@fastify/jwt' { interface FastifyJWT { payload: { sub: string email: string name: string apps: string[] permissions: string[] tenants?: Record bgp_tenant_id?: string is_admin?: boolean iss: string } user: { sub: string email: string name: string apps: string[] permissions: string[] tenants?: Record bgp_tenant_id?: string is_admin?: boolean iss: string } } } declare module 'fastify' { interface FastifyRequest { authUser?: AuthUser } } function asAppIds(apps: string[]): AppId[] { return apps.filter((a): a is AppId => (APP_IDS as readonly string[]).includes(a), ) } export function toMe(user: UserRow, apps: string[], permissions: string[]): MeResponse { return { id: user.id, email: user.email, name: user.name, is_admin: user.isAdmin, apps: asAppIds(apps), permissions, } } export function loadAuthUser( request: FastifyRequest, user: UserRow, ): AuthUser { const apps = getUserApps(request.server.db, user.id) let permissions = normalizePermissionKeys( getUserPermissions(request.server.db, user.id), ) if (user.isAdmin) { permissions = allPermissionKeys() } return { id: user.id, email: user.email, name: user.name, isAdmin: user.isAdmin, apps: asAppIds(apps), permissions, } } export async function requireAuth( request: FastifyRequest, reply: FastifyReply, ): Promise { try { await request.jwtVerify() } catch { return reply.status(401).send({ error: { code: 'UNAUTHORIZED', message: 'Требуется авторизация' }, }) } const sub = request.user.sub const row = getUserById(request.server.db, sub) if (!row || row.disabled) { return reply.status(401).send({ error: { code: 'UNAUTHORIZED', message: 'Пользователь недоступен' }, }) } request.authUser = loadAuthUser(request, row) } export async function requireAdmin( request: FastifyRequest, reply: FastifyReply, ): Promise { await requireAuth(request, reply) if (reply.sent) return if (!request.authUser?.isAdmin) { return reply.status(403).send({ error: { code: 'FORBIDDEN', message: 'Только для администраторов' }, }) } }