70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
import fastifyJwt from '@fastify/jwt';
|
|
import type { FastifyPluginAsync, preHandlerHookHandler } from 'fastify';
|
|
import fastifyPlugin from 'fastify-plugin';
|
|
import { config } from '../config.js';
|
|
import { pool } from '../db/pool.js';
|
|
|
|
export type UserRole = 'student' | 'instructor' | 'admin';
|
|
|
|
export interface AuthUser {
|
|
id: string;
|
|
email: string;
|
|
role: UserRole;
|
|
name: string;
|
|
}
|
|
|
|
declare module '@fastify/jwt' {
|
|
interface FastifyJWT {
|
|
payload: AuthUser;
|
|
user: AuthUser;
|
|
}
|
|
}
|
|
|
|
declare module 'fastify' {
|
|
interface FastifyInstance {
|
|
authenticate: preHandlerHookHandler;
|
|
requireRoles: (roles: UserRole[]) => preHandlerHookHandler;
|
|
}
|
|
}
|
|
|
|
const registerAuth: FastifyPluginAsync = async (app) => {
|
|
await app.register(fastifyJwt, { secret: config.JWT_SECRET });
|
|
|
|
const verifyActiveUser = async (request: { jwtVerify: () => Promise<void>; user: AuthUser }, reply: { code: (status: number) => { send: (payload: object) => unknown } }) => {
|
|
try {
|
|
await request.jwtVerify();
|
|
} catch {
|
|
reply.code(401).send({ error: 'Autenticação necessária.' });
|
|
return false;
|
|
}
|
|
|
|
const result = await pool.query<{ role: UserRole; display_name: string }>(
|
|
'select role, display_name from users where id = $1 and is_active = true',
|
|
[request.user.id],
|
|
);
|
|
const account = result.rows[0];
|
|
if (!account) {
|
|
reply.code(401).send({ error: 'Esta conta não está mais ativa.' });
|
|
return false;
|
|
}
|
|
|
|
request.user.role = account.role;
|
|
request.user.name = account.display_name;
|
|
return true;
|
|
};
|
|
|
|
app.decorate('authenticate', async (request, reply) => {
|
|
await verifyActiveUser(request, reply);
|
|
});
|
|
|
|
app.decorate('requireRoles', (roles: UserRole[]) => async (request, reply) => {
|
|
if (!(await verifyActiveUser(request, reply))) return;
|
|
|
|
if (!roles.includes(request.user.role)) {
|
|
return reply.code(403).send({ error: 'Você não tem permissão para esta ação.' });
|
|
}
|
|
});
|
|
};
|
|
|
|
export const authPlugin = fastifyPlugin(registerAuth, { name: 'auth' });
|