Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
1.9 kB ยท 50 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051import type { MiddlewareHandler } from "hono";import { HTTPException } from "hono/http-exception";
import type { Variables } from "@/types";
/** * V1 REST middleware that enforces the `'write'` scope on any * non-read HTTP method. Mounted on the V1 router, chained after * `authMiddleware`. * * Why a transport-level check on V1 specifically: the V1 routes * predate the services-first convention and currently do inline * Drizzle queries (zero `@openstatus/services` imports). Service-level * `requireScope` would silently skip every V1 write handler. This * middleware closes the gap. * * The HTTP-method-to-scope mapping is correct for V1 because every * V1 write route is a `POST`/`PUT`/`PATCH`/`DELETE` and every read * route is `GET`/`HEAD`. Includes `POST /v1/check` (on-demand * probe) โ POST is write per the plan's write-rule definition. * * After per-route migration to services, this stays as * defense-in-depth. */export function requireWriteScope(): MiddlewareHandler<{ Variables: Variables;}> { return async (c, next) => { const method = c.req.method; if (method === "GET" || method === "HEAD") return next();
const apiKey = c.get("apiKey"); // `authMiddleware` runs first and rejects requests with no key. // If we still see a missing key here, defer to it โ don't 403 a // request that's actually 401. if (!apiKey) return next();
// `?? []` is belt-and-braces: the type says `scopes` is non-optional, // but if `authMiddleware` ever errors after partially populating // `apiKey` we want fail-closed (no scopes = no write), not a crash // on `.includes`. const scopes = apiKey.scopes ?? []; if (!scopes.includes("write") && !scopes.includes("*")) { throw new HTTPException(403, { message: "API key lacks write scope", }); } return next(); };}