feat: add regex support to trusted-origins

- Add isTrustedOrigin() helper that matches exact strings, '*', or regex
  literals in the form /pattern/flags (e.g. /^.*\.example\.com$/i)
- Use isTrustedOrigin in authenticateOrigin() for --trusted-origins
- Add unit tests for isTrustedOrigin and for regex/wildcard in origin auth

Made-with: Cursor
This commit is contained in:
Mohammed Abdul Sattar 2026-03-09 14:52:07 -04:00
parent 1af5ce5ab6
commit 4a056b8736
2 changed files with 77 additions and 2 deletions

View file

@ -351,6 +351,33 @@ export function ensureOrigin(req: express.Request, _?: express.Response, next?:
}
}
/**
* Return true if the origin matches any trusted origin. Entries are matched
* as exact strings, the special wildcard `"*"`, or regex literals in the form
* `/pattern/flags` (e.g. `/^.*\.example\.com$/i`).
*/
export function isTrustedOrigin(origin: string, trustedOrigins: string[]): boolean {
return trustedOrigins.some((trusted) => {
if (trusted === "*" || trusted === origin) {
return true
}
// Regex literal: /pattern/ or /pattern/flags
if (trusted.startsWith("/")) {
const closingSlash = trusted.lastIndexOf("/")
if (closingSlash > 0) {
const pattern = trusted.slice(1, closingSlash)
const flags = trusted.slice(closingSlash + 1)
try {
return new RegExp(pattern, flags).test(origin)
} catch {
return false
}
}
}
return false
})
}
/**
* Authenticate the request origin against the host. Throw if invalid.
*/
@ -370,7 +397,7 @@ export function authenticateOrigin(req: express.Request): void {
}
const trustedOrigins = req.args["trusted-origins"] || []
if (trustedOrigins.includes(origin) || trustedOrigins.includes("*")) {
if (isTrustedOrigin(origin, trustedOrigins)) {
return
}

View file

@ -19,6 +19,36 @@ describe("http", () => {
expect(http.relativeRoot("/foo/bar/")).toStrictEqual("./../..")
})
describe("isTrustedOrigin", () => {
it("should match exact origins", () => {
expect(http.isTrustedOrigin("localhost:8080", ["localhost:8080"])).toBe(true)
expect(http.isTrustedOrigin("example.com", ["example.com"])).toBe(true)
expect(http.isTrustedOrigin("example.com", ["other.com"])).toBe(false)
})
it("should match the wildcard *", () => {
expect(http.isTrustedOrigin("anything.example.com", ["*"])).toBe(true)
expect(http.isTrustedOrigin("localhost:8080", ["*"])).toBe(true)
})
it("should match regex patterns", () => {
expect(http.isTrustedOrigin("sub.example.com", ["/\\.example\\.com$/"])).toBe(true)
expect(http.isTrustedOrigin("evil.com", ["/\\.example\\.com$/"])).toBe(false)
})
it("should support regex flags", () => {
expect(http.isTrustedOrigin("SUB.EXAMPLE.COM", ["/\\.example\\.com$/i"])).toBe(true)
})
it("should return false for invalid regex patterns", () => {
expect(http.isTrustedOrigin("example.com", ["/[invalid/"])).toBe(false)
})
it("should return false for an empty trusted origins list", () => {
expect(http.isTrustedOrigin("example.com", [])).toBe(false)
})
})
describe("origin", () => {
;[
{
@ -54,6 +84,22 @@ describe("http", () => {
host: "localhost:8080",
expected: "malformed", // Parsing fails completely.
},
{
origin: "http://sub.example.com",
host: "other.com",
trustedOrigins: ["/\\.example\\.com$/"],
},
{
origin: "http://evil.com",
host: "other.com",
trustedOrigins: ["/\\.example\\.com$/"],
expected: "does not match",
},
{
origin: "http://sub.example.com",
host: "other.com",
trustedOrigins: ["*"],
},
].forEach((test) => {
;[
["host", test.host],
@ -70,7 +116,9 @@ describe("http", () => {
origin: test.origin,
[key]: value,
},
args: {},
args: {
"trusted-origins": (test as { trustedOrigins?: string[] }).trustedOrigins,
},
})
if (typeof test.expected === "string") {
expect(() => http.authenticateOrigin(req)).toThrow(test.expected)