Gateway/Security: protect /api/channels plugin root

This commit is contained in:
Brian Mendonca
2026-02-24 12:14:35 -07:00
committed by Peter Steinberger
parent 453664f09d
commit 5a64f6d766
2 changed files with 17 additions and 1 deletions

View File

@@ -491,7 +491,7 @@ export function createGatewayHttpServer(opts: {
// Channel HTTP endpoints are gateway-auth protected by default.
// Non-channel plugin routes remain plugin-owned and must enforce
// their own auth when exposing sensitive functionality.
if (requestPath.startsWith("/api/channels/")) {
if (requestPath === "/api/channels" || requestPath.startsWith("/api/channels/")) {
const token = getBearerToken(req);
const authResult = await authorizeHttpGatewayConnect({
auth: resolvedAuth,

View File

@@ -142,6 +142,12 @@ describe("gateway plugin HTTP auth boundary", () => {
run: async () => {
const handlePluginRequest = vi.fn(async (req: IncomingMessage, res: ServerResponse) => {
const pathname = new URL(req.url ?? "/", "http://localhost").pathname;
if (pathname === "/api/channels") {
res.statusCode = 200;
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.end(JSON.stringify({ ok: true, route: "channel-root" }));
return true;
}
if (pathname === "/api/channels/nostr/default/profile") {
res.statusCode = 200;
res.setHeader("Content-Type", "application/json; charset=utf-8");
@@ -179,6 +185,16 @@ describe("gateway plugin HTTP auth boundary", () => {
expect(unauthenticated.getBody()).toContain("Unauthorized");
expect(handlePluginRequest).not.toHaveBeenCalled();
const unauthenticatedRoot = createResponse();
await dispatchRequest(
server,
createRequest({ path: "/api/channels" }),
unauthenticatedRoot.res,
);
expect(unauthenticatedRoot.res.statusCode).toBe(401);
expect(unauthenticatedRoot.getBody()).toContain("Unauthorized");
expect(handlePluginRequest).not.toHaveBeenCalled();
const authenticated = createResponse();
await dispatchRequest(
server,