(Feat-Fix): Lots of fixes done, reporting system fixed, stricter types

This commit is contained in:
2025-12-19 18:48:05 +00:00
parent 01400ad4e1
commit 865e0bf00e
61 changed files with 10072 additions and 6645 deletions

View File

@@ -1,5 +1,5 @@
import { Context, Next } from "@oak/oak";
import { verify, create, getNumericDate } from "djwt";
import { create, getNumericDate, verify } from "djwt";
import { config } from "../config/env.ts";
import type { JWTPayload, UserRole } from "../types/index.ts";
@@ -12,14 +12,16 @@ const cryptoKey = await crypto.subtle.importKey(
keyData,
{ name: "HMAC", hash: "SHA-256" },
false,
["sign", "verify"]
["sign", "verify"],
);
// Generate JWT token
export async function generateToken(payload: Omit<JWTPayload, "exp" | "iat">): Promise<string> {
export async function generateToken(
payload: Omit<JWTPayload, "exp" | "iat">,
): Promise<string> {
const expiresIn = config.JWT_EXPIRES_IN;
let expSeconds = 7 * 24 * 60 * 60; // Default 7 days
if (expiresIn.endsWith("d")) {
expSeconds = parseInt(expiresIn) * 24 * 60 * 60;
} else if (expiresIn.endsWith("h")) {
@@ -27,7 +29,7 @@ export async function generateToken(payload: Omit<JWTPayload, "exp" | "iat">): P
} else if (expiresIn.endsWith("m")) {
expSeconds = parseInt(expiresIn) * 60;
}
const token = await create(
{ alg: "HS256", typ: "JWT" },
{
@@ -35,9 +37,9 @@ export async function generateToken(payload: Omit<JWTPayload, "exp" | "iat">): P
exp: getNumericDate(expSeconds),
iat: getNumericDate(0),
},
cryptoKey
cryptoKey,
);
return token;
}
@@ -52,24 +54,27 @@ export async function verifyToken(token: string): Promise<JWTPayload | null> {
}
// Authentication middleware
export async function authenticateToken(ctx: Context, next: Next): Promise<void> {
export async function authenticateToken(
ctx: Context,
next: Next,
): Promise<void> {
const authHeader = ctx.request.headers.get("Authorization");
const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
if (!token) {
ctx.response.status = 401;
ctx.response.body = { error: "Access token required" };
return;
}
const payload = await verifyToken(token);
if (!payload) {
ctx.response.status = 403;
ctx.response.body = { error: "Invalid or expired token" };
return;
}
// Attach user to context state
ctx.state.user = payload;
await next();
@@ -79,19 +84,19 @@ export async function authenticateToken(ctx: Context, next: Next): Promise<void>
export function authorize(...roles: UserRole[]) {
return async (ctx: Context, next: Next): Promise<void> => {
const user = ctx.state.user as JWTPayload | undefined;
if (!user) {
ctx.response.status = 401;
ctx.response.body = { error: "Unauthorized" };
return;
}
if (!roles.includes(user.role)) {
ctx.response.status = 403;
ctx.response.body = { error: "Insufficient permissions" };
return;
}
await next();
};
}