fix(files): honor forwarded HTTPS proxy chains (#92)
Some checks failed
CI / build (push) Has been cancelled
deploy / deploy (push) Has been cancelled
test / test (push) Has been cancelled

Co-authored-by: rissrice2105-agent <rissrice2105-agent@users.noreply.github.com>
This commit is contained in:
RissRIce 2026-07-15 07:21:31 -06:00 committed by GitHub
parent 2048229cbb
commit 24269b6799
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 27 additions and 1 deletions

View file

@ -115,7 +115,11 @@ func (h *webSrv) clear(w http.ResponseWriter, r *http.Request) {
} }
func secureReq(r *http.Request) bool { func secureReq(r *http.Request) bool {
return r.TLS != nil || strings.EqualFold(r.Header.Get("X-Forwarded-Proto"), "https") if r.TLS != nil {
return true
}
proto, _, _ := strings.Cut(r.Header.Get("X-Forwarded-Proto"), ",")
return strings.EqualFold(strings.TrimSpace(proto), "https")
} }
func randHex(n int) string { func randHex(n int) string {

View file

@ -61,6 +61,28 @@ func TestWebRequiresAuth(t *testing.T) {
} }
} }
func TestSecureReqUsesFirstForwardedProto(t *testing.T) {
for _, tc := range []struct {
name string
proto string
secure bool
}{
{name: "https", proto: "https", secure: true},
{name: "proxy chain", proto: "https, http", secure: true},
{name: "case and whitespace", proto: " HTTPS , http", secure: true},
{name: "http", proto: "http", secure: false},
{name: "untrusted later value", proto: "http, https", secure: false},
} {
t.Run(tc.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("X-Forwarded-Proto", tc.proto)
if got := secureReq(req); got != tc.secure {
t.Fatalf("secureReq() = %v, want %v for %q", got, tc.secure, tc.proto)
}
})
}
}
func TestWebRoundTrip(t *testing.T) { func TestWebRoundTrip(t *testing.T) {
h, _ := webTestHandler(t) h, _ := webTestHandler(t)