// Copyright (C) 2026 Dcntrlized // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package web import ( "bytes" "context" "encoding/json" "io" "net/http" "time" "git.dcntrlized.org/dcntrlized/dcntrlized-auth/authproxy" ) const maxHubBody = 1 << 20 // 1 MiB // hubClient is the outbound hub transport. Contract rev 9 removed the mTLS // identity layer fleet-wide, so this is a plain HTTP client — no client // certificate and no custom TLS configuration. The timeout bounds the whole // hub exchange so a stalled hub cannot pin a browser request. var hubClient = &http.Client{Timeout: 10 * time.Second} // callHub performs one fixed hub /auth/* call over the plaintext internal // network. It deliberately does NOT use authproxy.Proxy: that helper copies // every inbound header (including Cookie and X-Access-Token) to the hub, which // is forbidden on the browser edge. func callHub(ctx context.Context, method, path string, payload any) (int, []byte, error) { var body io.Reader if payload != nil { raw, err := json.Marshal(payload) if err != nil { return 0, nil, err } body = bytes.NewReader(raw) } req, err := http.NewRequestWithContext(ctx, method, authproxy.Target()+"/auth/"+path, body) if err != nil { return 0, nil, err } req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") resp, err := hubClient.Do(req) if err != nil { return 0, nil, err } defer resp.Body.Close() out, err := io.ReadAll(io.LimitReader(resp.Body, maxHubBody)) if err != nil { return 0, nil, err } return resp.StatusCode, out, nil }