/* catcrafts.net Copyright (C) 2026 Catcrafts The source code of this website is made available for viewing purposes only. No permission is granted to copy, modify, distribute, or create derivative works. */ // Request provenance: the forwarded-address parser the rate limiter keys on, // and the Origin check that gates the order form. import std; import Catcrafts.Shared; import Catcrafts.Server; using namespace Catcrafts; namespace { int failures = 0; void Check(bool ok, std::string_view what, std::string_view got = {}) { if (ok) return; ++failures; std::println(std::cerr, "FAIL: {}{}{}", what, got.empty() ? "" : " got: ", got); } } // namespace int main() { // The rate limiter keys on this, so getting the WRONG end of the header // is not a cosmetic bug: the leftmost entry is client-controlled, and // trusting it would hand every attacker an endless supply of identities. { using Server::ClientAddressFromForwarded; Check(ClientAddressFromForwarded("203.0.113.7") == "203.0.113.7", "forwarded: single entry"); Check(ClientAddressFromForwarded("198.51.100.4, 203.0.113.7") == "203.0.113.7", "forwarded: rightmost entry wins"); // The attack this exists to defeat: a client that sends its own header // to look like a different peer. Caddy appends the truth on the right. Check(ClientAddressFromForwarded("1.1.1.1, 2.2.2.2, 203.0.113.7") == "203.0.113.7", "forwarded: spoofed prefix ignored"); Check(ClientAddressFromForwarded("198.51.100.4, 203.0.113.7") == "203.0.113.7", "forwarded: padding trimmed"); Check(ClientAddressFromForwarded("2001:db8::1") == "2001:db8::1", "forwarded: ipv6 passes through"); Check(ClientAddressFromForwarded("").empty(), "forwarded: empty stays empty"); // No header at all means nothing proxied this request; the caller must // see an empty peer and fall back to the global budget. Check(ClientAddressFromForwarded("198.51.100.4, ").empty(), "forwarded: empty last entry is no peer"); } { using Server::OriginAllowed; Check(OriginAllowed("https://catcrafts.net", "https://catcrafts.net"), "origin: same origin allowed"); Check(OriginAllowed("https://catcrafts.net", "https://catcrafts.net/"), "origin: trailing slash on the base normalised"); // A non-browser client (curl, the e2e suite) sends no Origin and // cannot be a cross-site forgery — there is no session to ride on. Check(OriginAllowed("", "https://catcrafts.net"), "origin: absent allowed"); Check(!OriginAllowed("https://evil.example", "https://catcrafts.net"), "origin: foreign origin refused"); // Neither a subdomain nor a lookalike is us. Check(!OriginAllowed("https://catcrafts.net.evil.example", "https://catcrafts.net"), "origin: suffix lookalike refused"); Check(!OriginAllowed("https://shop.catcrafts.net", "https://catcrafts.net"), "origin: subdomain refused"); // Scheme is part of an origin: http is not https. Check(!OriginAllowed("http://catcrafts.net", "https://catcrafts.net"), "origin: scheme mismatch refused"); // A sandboxed iframe posts Origin: null. Present, and not us. Check(!OriginAllowed("null", "https://catcrafts.net"), "origin: null refused"); Check(!OriginAllowed("https://catcrafts.net", ""), "origin: unconfigured base refuses rather than accepts all"); // dev.sh serves on localhost and sets --redirect-base to match. Check(OriginAllowed("http://localhost:8080", "http://localhost:8080"), "origin: dev localhost base matches"); } if (failures != 0) { std::println(std::cerr, "{} check(s) failed", failures); return 1; } return 0; }