feat(deploy) : serve sudloh.com alongside guide.sudloh.com
CI / Verify (push) Successful in 2m17s
CI / Build immutable images and deploy (push) Successful in 1m59s

This commit is contained in:
2026-10-15 02:09:06 +07:00 Unverified
parent 6acad81b05
commit e11dede099
11 changed files with 83 additions and 13 deletions
+17
View File
@@ -3,10 +3,13 @@ import { boundedBody, errorResponse, HttpError, readJson, requireSameOrigin, wit
import { trustedClientAddress } from "./rate-limit";
const originalAuthUrl = process.env.BETTER_AUTH_URL;
const originalTrustedOrigins = process.env.BETTER_AUTH_TRUSTED_ORIGINS;
const originalClientIpHeader = process.env.TRUSTED_CLIENT_IP_HEADER;
afterEach(() => {
vi.restoreAllMocks();
if (originalTrustedOrigins === undefined) delete process.env.BETTER_AUTH_TRUSTED_ORIGINS;
else process.env.BETTER_AUTH_TRUSTED_ORIGINS = originalTrustedOrigins;
if (originalAuthUrl === undefined) delete process.env.BETTER_AUTH_URL;
else process.env.BETTER_AUTH_URL = originalAuthUrl;
if (originalClientIpHeader === undefined) delete process.env.TRUSTED_CLIENT_IP_HEADER;
@@ -14,6 +17,20 @@ afterEach(() => {
});
describe("request boundaries", () => {
it("allows both configured domains while rejecting unlisted origins", () => {
process.env.BETTER_AUTH_URL = "https://guide.sudloh.com";
process.env.BETTER_AUTH_TRUSTED_ORIGINS = "https://guide.sudloh.com, https://sudloh.com";
for (const origin of ["https://guide.sudloh.com", "https://sudloh.com"]) {
expect(() => requireSameOrigin(new Request("http://internal", { headers: { origin } }))).not.toThrow();
}
for (const origin of ["http://sudloh.com", "https://evil.sudloh.com", "https://sudloh.com.evil.test"]) {
expect(() => requireSameOrigin(new Request("http://internal", { headers: { origin } }))).toThrow("cross-origin");
}
expect(() => requireSameOrigin(new Request("http://internal", {
headers: { origin: "https://sudloh.com", "sec-fetch-site": "cross-site" },
}))).toThrow("cross-origin");
});
it("compares origin to configuration, not attacker-controlled Host", () => {
process.env.BETTER_AUTH_URL = "https://guide.example.test";
expect(() => requireSameOrigin(new Request("https://evil.test", { headers: { origin: "https://evil.test", host: "evil.test" } }))).toThrow("cross-origin");
+4 -1
View File
@@ -25,8 +25,11 @@ export function errorResponse(cause: unknown): Response {
export function requireSameOrigin(request: Request) {
const configured = process.env.BETTER_AUTH_URL;
if (!configured) throw new HttpError(503, "origin-not-configured");
const allowedOrigins = [new URL(configured).origin, ...(
process.env.BETTER_AUTH_TRUSTED_ORIGINS?.split(",").map((value) => value.trim()).filter(Boolean) ?? []
)];
const origin = request.headers.get("origin");
if (origin !== new URL(configured).origin || request.headers.get("sec-fetch-site") === "cross-site") {
if (!origin || !allowedOrigins.includes(origin) || request.headers.get("sec-fetch-site") === "cross-site") {
throw new HttpError(403, "cross-origin-request");
}
}