Documentation
¶
Overview ¶
Package httputil provides HTTP response helper functions for writing JSON responses.
Index ¶
- Constants
- func ClientIPFromContext(ctx context.Context) string
- func ObfuscatedIP(s string) string
- func RedactDSN(err error) error
- func SafeLogValue(s string) string
- func WithClientIP(ctx context.Context, ip string) context.Context
- func WriteBearerError(w http.ResponseWriter, status int, message string, c BearerChallenge)
- func WriteError(w http.ResponseWriter, status int, message string)
- func WriteJSON(w http.ResponseWriter, status int, data any)
- type BearerChallenge
Constants ¶
const ( // BearerErrInvalidRequest — the request is malformed: the credential was // sent more than one way, or a required parameter is missing. BearerErrInvalidRequest = "invalid_request" // BearerErrInvalidToken — the credential presented is expired, revoked, // malformed, or otherwise unusable. BearerErrInvalidToken = "invalid_token" // BearerErrInsufficientScope — the credential is valid but does not carry // the scope this resource requires. BearerErrInsufficientScope = "insufficient_scope" )
RFC 6750 §3.1 error codes. These are the whole registry that section defines; nothing else may appear in the "error" attribute of a Bearer challenge.
const BearerRealm = "vault42"
BearerRealm names the RFC 7235 protection space that vault42's bearer-token endpoints share. Every access token is minted for the same issuer and audience, so there is exactly one realm and it is a constant rather than a per-route string.
Variables ¶
This section is empty.
Functions ¶
func ClientIPFromContext ¶ added in v1.0.3
ClientIPFromContext returns the address WithClientIP stored, or "" when the context did not come through the HTTP edge (background sweepers, CLI, tests).
An empty result must always be safe to act on: it means "source unknown", not "source trusted".
func ObfuscatedIP ¶ added in v0.6.7
ObfuscatedIP returns a privacy-preserving rendering of an IP address suitable for logs. IPv4 has its last octet zeroed (192.168.1.42 -> 192.168.1.0); IPv6 has its lower 64 bits zeroed (2001:db8::1 -> 2001:db8::). Returns "invalid_ip" for unparseable input. This satisfies CWE-359 / GDPR pseudonymization requirements while preserving /24 (or /64) granularity for rate-limit and abuse-pattern correlation.
A "host:port" pair is accepted and masked as its host, because that is the shape of r.RemoteAddr and a caller who has only that should not have to remember to split it first. Rejecting it would be the worse failure of the two: the address would be replaced by "invalid_ip" rather than by its network, so the line would lose its diagnostic without anything reporting a problem.
func RedactDSN ¶ added in v1.0.3
RedactDSN strips connection-URL credentials from an error message.
pgx puts the DSN it dialed into its connect errors, so any tool that logs one raw prints the database password. This is the shared home for the redaction that cmd/vault and cmd/admin-gateway each carry a private copy of; cmd/recover had none at all, which mattered most because it is the tool that always holds the production DSN.
The message is rebuilt with fmt.Errorf("%s", ...) rather than wrapped: keeping the cause in the chain would let errors.As reach it and print the unredacted original.
func SafeLogValue ¶
SafeLogValue replaces every character that can forge a log record or drive a terminal with '_', to prevent log injection (CWE-117, OWASP). Use on any value logged that could theoretically contain attacker-influenced data.
The set is wider than CR/LF/NUL/tab because a log line has two readers and each has its own escape hatch. A log shipper splits records on U+0085, U+2028 and U+2029 as readily as on a newline. A terminal acts on what it is sent: ESC opens a control sequence that can clear the screen, reposition the cursor over records already printed, or set the window title, U+009B opens the same sequence on its own in 8-bit mode, and backspace alone is enough to rewrite a line as it is drawn. Neutralizing only the characters that end a line would leave an operator's terminal as the injection point.
func WithClientIP ¶ added in v1.0.3
WithClientIP returns a context carrying the resolved client address.
It lives here rather than in the middleware package so the service layer, which only ever receives a context, can key per-source state on the same address the rate limiter used without importing the HTTP middleware.
func WriteBearerError ¶ added in v1.0.3
func WriteBearerError(w http.ResponseWriter, status int, message string, c BearerChallenge)
WriteBearerError writes the RFC 6750 challenge header and the JSON error body together, so a rejection cannot ship one without the other.
func WriteError ¶
func WriteError(w http.ResponseWriter, status int, message string)
WriteError writes a JSON error response with the given status code and message.
Types ¶
type BearerChallenge ¶ added in v1.0.3
BearerChallenge is the WWW-Authenticate value RFC 6750 §3 requires on a 401 or 403 from a bearer-protected resource.
An empty Error means a bare challenge, which is what §3 mandates when the request presented no bearer credential at all: naming an error code would describe a credential the client never sent, and leaks whether a guessed token was well-formed. Scope is set only alongside insufficient_scope, where §3 defines it as the scope required to reach the resource.
func (BearerChallenge) String ¶ added in v1.0.3
func (c BearerChallenge) String() string
String renders the challenge as a WWW-Authenticate header value.