Files
kunthawat 2d1be52177 Emdash source with visual editor image upload fix
Fixes:
1. media.ts: wrap placeholder generation in try-catch
2. toolbar.ts: check r.ok, display error message in popover
2026-05-03 10:44:54 +07:00

98 lines
3.6 KiB
TypeScript

/**
* Tests for getTrustedProxyHeaders — resolves the list of trusted client-IP
* headers from config, falling back to the EMDASH_TRUSTED_PROXY_HEADERS env
* var, then to an empty array.
*
* The helper lets operators declare which headers they trust when running
* behind a reverse proxy. On Cloudflare the `cf` object is used instead and
* this list is usually empty.
*/
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
_resetTrustedProxyHeadersCache,
getTrustedProxyHeaders,
} from "../../../src/auth/trusted-proxy.js";
describe("getTrustedProxyHeaders", () => {
const ORIGINAL_ENV = process.env.EMDASH_TRUSTED_PROXY_HEADERS;
beforeEach(() => {
_resetTrustedProxyHeadersCache();
});
afterEach(() => {
if (ORIGINAL_ENV === undefined) {
delete process.env.EMDASH_TRUSTED_PROXY_HEADERS;
} else {
process.env.EMDASH_TRUSTED_PROXY_HEADERS = ORIGINAL_ENV;
}
_resetTrustedProxyHeadersCache();
});
it("returns config value when set", () => {
expect(getTrustedProxyHeaders({ trustedProxyHeaders: ["x-real-ip"] })).toEqual(["x-real-ip"]);
});
it("prefers config over env", () => {
process.env.EMDASH_TRUSTED_PROXY_HEADERS = "fly-client-ip";
expect(getTrustedProxyHeaders({ trustedProxyHeaders: ["x-real-ip"] })).toEqual(["x-real-ip"]);
});
it("falls back to env when config is absent", () => {
process.env.EMDASH_TRUSTED_PROXY_HEADERS = "x-real-ip,fly-client-ip";
expect(getTrustedProxyHeaders(undefined)).toEqual(["x-real-ip", "fly-client-ip"]);
});
it("trims whitespace and drops empty entries from env", () => {
process.env.EMDASH_TRUSTED_PROXY_HEADERS = " x-real-ip , , fly-client-ip ";
expect(getTrustedProxyHeaders(undefined)).toEqual(["x-real-ip", "fly-client-ip"]);
});
it("lowercases header names for consistent matching", () => {
// Header lookups go through Headers.get() which is case-insensitive,
// so we normalise the list here to avoid double-normalising elsewhere.
expect(getTrustedProxyHeaders({ trustedProxyHeaders: ["X-Real-IP", "Fly-Client-IP"] })).toEqual(
["x-real-ip", "fly-client-ip"],
);
});
it("returns empty array when neither config nor env is set", () => {
delete process.env.EMDASH_TRUSTED_PROXY_HEADERS;
expect(getTrustedProxyHeaders(undefined)).toEqual([]);
});
it("returns empty array when config has empty list", () => {
process.env.EMDASH_TRUSTED_PROXY_HEADERS = "x-real-ip";
// An explicit empty array means "trust nothing" — do not fall through
// to the env. Operators use this to override an inherited env value.
expect(getTrustedProxyHeaders({ trustedProxyHeaders: [] })).toEqual([]);
});
// Header names must be valid RFC 7230 tokens; passing anything else into
// `Headers.get()` throws. Drop invalid entries silently rather than
// taking down every rate-limited endpoint with a 500.
it("drops invalid header names from config", () => {
expect(
getTrustedProxyHeaders({
trustedProxyHeaders: ["x-real-ip", "", "invalid name", "bad:colon", "ok-name"],
}),
).toEqual(["x-real-ip", "ok-name"]);
});
it("drops invalid header names from env", () => {
process.env.EMDASH_TRUSTED_PROXY_HEADERS = "x-real-ip, x y z , bad:one, ok-name";
expect(getTrustedProxyHeaders(undefined)).toEqual(["x-real-ip", "ok-name"]);
});
it("trims whitespace from config entries before matching", () => {
// Common typo: `"x-real-ip "` (trailing space). Previously the raw
// value was lowercased but not trimmed, so validation silently
// dropped it and per-IP bucketing was disabled.
expect(
getTrustedProxyHeaders({ trustedProxyHeaders: [" x-real-ip ", "fly-client-ip"] }),
).toEqual(["x-real-ip", "fly-client-ip"]);
});
});