File
Blob: tests/worker/security/same-origin.test.ts
| 1 | import { env } from "cloudflare:workers"; |
| 2 | import { Hono } from "hono"; |
| 3 | import { describe, expect, it } from "vitest"; |
| 4 | |
| 5 | import type { AppEnv } from "@/worker/hono"; |
| 6 | import { HttpError, toErrorResponse } from "@/worker/http"; |
| 7 | import { requireSameOrigin } from "@/worker/security/same-origin"; |
| 8 | |
| 9 | const buildApp = () => { |
| 10 | const app = new Hono<AppEnv>(); |
| 11 | app.use("*", requireSameOrigin); |
| 12 | app.all("/guarded", (c) => c.json({ ok: true })); |
| 13 | app.onError((error, c) => toErrorResponse(c, error instanceof Error ? error : new HttpError(500, "error", "error"))); |
| 14 | return app; |
| 15 | }; |
| 16 | |
| 17 | const fetchGuarded = async (method: string, headers?: HeadersInit): Promise<Response> => |
| 18 | await buildApp().fetch(new Request("https://example.com/guarded", { method, headers }), env); |
| 19 | |
| 20 | describe("same-origin guard", () => { |
| 21 | it("skips safe methods", async () => { |
| 22 | expect((await fetchGuarded("GET")).status).toBe(200); |
| 23 | }); |
| 24 | |
| 25 | it("allows same-origin Origin and trusted Fetch Metadata", async () => { |
| 26 | expect((await fetchGuarded("POST", { origin: "https://example.com" })).status).toBe(200); |
| 27 | expect((await fetchGuarded("POST", { "sec-fetch-site": "none" })).status).toBe(200); |
| 28 | }); |
| 29 | |
| 30 | it("rejects missing and cross-origin unsafe requests", async () => { |
| 31 | const missingOrigin = await fetchGuarded("POST"); |
| 32 | expect(missingOrigin.status).toBe(403); |
| 33 | |
| 34 | const crossOrigin = await fetchGuarded("POST", { origin: "https://evil.example" }); |
| 35 | expect(crossOrigin.status).toBe(403); |
| 36 | await expect(crossOrigin.json()).resolves.toMatchObject({ |
| 37 | error: { |
| 38 | code: "cross_origin_blocked", |
| 39 | }, |
| 40 | }); |
| 41 | }); |
| 42 | }); |