feat: security and auditing

This commit is contained in:
2026-02-04 16:48:08 -08:00
parent 11be34cd21
commit 0a654f423a
42 changed files with 2195 additions and 160 deletions
+92
View File
@@ -0,0 +1,92 @@
/**
* @copyright 2026 NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { FastifyPluginAsync } from "fastify";
import { User, AuditAction, AuditCategory } from "@library/shared-types";
import { UserService } from "../../services/user.service";
import { AuditService } from "../../services/audit.service";
import { adminGuard } from "../../middleware/admin-guard";
const usersRoutes: FastifyPluginAsync = async (app) => {
const userService = new UserService();
app.get<{ Reply: User[] }>(
"/",
{
preValidation: [app.authenticate, adminGuard],
},
async () => {
return userService.getAllUsers();
}
);
app.get<{ Params: { id: string }; Reply: User | null }>(
"/:id",
{
preValidation: [app.authenticate, adminGuard],
},
async (request) => {
const { id } = request.params;
return userService.getUserById(id);
}
);
app.post<{ Params: { id: string }; Reply: User | { error: string } }>(
"/:id/ban",
{
preValidation: [app.authenticate, adminGuard],
preHandler: [app.csrfProtection],
},
async (request, reply) => {
const { id } = request.params;
const currentUser = request.user as { id: string };
if (currentUser.id === id) {
return reply.code(400).send({ error: "You cannot ban yourself" });
}
const user = await userService.banUser(id);
if (!user) {
return reply.code(404).send({ error: "User not found" });
}
await AuditService.logFromRequest(request, {
action: AuditAction.USER_BAN,
category: AuditCategory.ADMIN,
targetUserId: id,
details: `Banned user: ${user.username}`,
});
return user;
}
);
app.post<{ Params: { id: string }; Reply: User | { error: string } }>(
"/:id/unban",
{
preValidation: [app.authenticate, adminGuard],
preHandler: [app.csrfProtection],
},
async (request, reply) => {
const { id } = request.params;
const user = await userService.unbanUser(id);
if (!user) {
return reply.code(404).send({ error: "User not found" });
}
await AuditService.logFromRequest(request, {
action: AuditAction.USER_UNBAN,
category: AuditCategory.ADMIN,
targetUserId: id,
details: `Unbanned user: ${user.username}`,
});
return user;
}
);
};
export default usersRoutes;