import assert from "node:assert/strict" import Fastify from "fastify" import { SignJWT } from "jose" process.env.AUTH_REQUIRED = "true" process.env.AUTH_JWT_SECRET = "geoip-test-secret" process.env.AUTH_ISSUER = "https://auth.test.local" process.env.NODE_ENV = "test" const { default: authPlugin, requireAuth } = await import("./auth.js") const { permissionForRequest } = await import("../lib/permissions.js") assert.equal(permissionForRequest("GET", "/api/geoip"), "mm:traffic:read") assert.equal(permissionForRequest("PUT", "/api/geoip"), "mm:traffic:write") assert.equal(permissionForRequest("POST", "/api/geoip/update?force=true"), "mm:traffic:write") const app = Fastify(); await app.register(authPlugin); app.addHook("preHandler", requireAuth) let applied = 0 app.get("/api/geoip", async () => ({ known: true })) app.put("/api/geoip", async () => { applied++; return { ok: true } }) app.post("/api/geoip/update", async () => { applied++; return { ok: true } }) for (const permission of ["mm:dashboard:read", "mm:traffic:read", "mm:traffic:write", "mm:traffic:admin", "mm:settings:admin"]) { const token = await new SignJWT({ sub: "fixture", apps: ["mm"], permissions: [permission] }).setProtectedHeader({ alg: "HS256" }).setIssuer("https://auth.test.local").setExpirationTime("1h").sign(new TextEncoder().encode("geoip-test-secret")) for (const [method, url] of [["GET", "/api/geoip"], ["PUT", "/api/geoip"], ["POST", "/api/geoip/update"]] as const) { const before = applied; const response = await app.inject({ method, url, headers: { authorization: "Bearer " + token } }) const allowed = permission === "mm:traffic:write" || permission === "mm:traffic:admin" || (method === "GET" && permission === "mm:traffic:read") assert.equal(response.statusCode, allowed ? 200 : 403); assert.equal(applied, before + (allowed && method !== "GET" ? 1 : 0)) } } assert.equal((await app.inject({ method: "POST", url: "/api/geoip/update" })).statusCode, 401) await app.close(); console.log("GeoIP JWT gate: reader cannot mutate, writer/admin authorized before handler")