Files
app/src/middleware/auth.ts
BOHA 907ee574e6 chore(lint): remove all 34 dead-code warnings (verified site by site)
unused-vars (25): leftover imports/types across pages, routes and services;
write-only sickHours accumulator; unused holidayCount pair; test helpers
authPatch/authDelete; TOut dropped from ApiMutationOptions (the hook keeps
its own generic — no call-site changes); requireAuth no longer importable
in customers/warehouse routes (matches the no-bare-auth-reads convention).

useless-assignment (5): initializers proven overwritten on every path
(systemQty x2, hours, writtenSize -> let x: number) and the seed's dead
adminUser reassignment (create kept, assignment dropped).

useless-escape (4): [eE+\-] -> [eE+-] and [\/...] -> [/...] — identical
semantics.

Behavior-neutral; lint 102 -> 68 warnings (0 errors), suite 641 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 00:13:52 +02:00

78 lines
2.0 KiB
TypeScript

import { FastifyRequest, FastifyReply } from "fastify";
import { verifyAccessToken } from "../services/auth";
import { error } from "../utils/response";
export async function requireAuth(
request: FastifyRequest,
reply: FastifyReply,
): Promise<void> {
const authHeader = request.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) {
return error(reply, "Vyžadována autentizace", 401);
}
const token = authHeader.slice(7);
const authData = await verifyAccessToken(token);
if (!authData) {
return error(reply, "Neplatný nebo expirovaný token", 401);
}
request.authData = authData;
}
export async function optionalAuth(
request: FastifyRequest,
_reply: FastifyReply,
): Promise<void> {
const authHeader = request.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) return;
const token = authHeader.slice(7);
request.authData = (await verifyAccessToken(token)) ?? undefined;
}
export function requirePermission(...permissionNames: string[]) {
return async (
request: FastifyRequest,
reply: FastifyReply,
): Promise<void> => {
await requireAuth(request, reply);
if (reply.sent) return;
const authData = request.authData!;
// Admin has all permissions
if (authData.roleName === "admin") return;
const hasAll = permissionNames.every((p) =>
authData.permissions.includes(p),
);
if (!hasAll) {
return error(reply, "Nedostatečná oprávnění", 403);
}
};
}
export function requireAnyPermission(...permissionNames: string[]) {
return async (
request: FastifyRequest,
reply: FastifyReply,
): Promise<void> => {
await requireAuth(request, reply);
if (reply.sent) return;
const authData = request.authData!;
// Admin has all permissions
if (authData.roleName === "admin") return;
const hasAny = permissionNames.some((p) =>
authData.permissions.includes(p),
);
if (!hasAny) {
return error(reply, "Nedostatečná oprávnění", 403);
}
};
}