feat: publish Gamertan Web Foundations preview source
verify / verify (push) Successful in 2m55s

Export the reviewed application-neutral package set through the exact public allowlist. Development history and private application evidence remain outside this canonical source root.

Developed with material AI assistance under maintainer review.

Signed-off-by: Cole Speelman <crspeelman@gmail.com>
This commit is contained in:
2026-08-16 15:05:40 -04:00
commit 3a4b6db9b8
54 changed files with 4523 additions and 0 deletions
+224
View File
@@ -0,0 +1,224 @@
// SPDX-License-Identifier: MPL-2.0
// Package requestmeta resolves bounded request identity and reverse-proxy
// metadata once so security, logging, and application middleware agree.
package requestmeta
import (
"context"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/netip"
"strings"
)
const maxForwardedHeader = 4096
var ErrInvalidForwarding = errors.New("requestmeta: invalid trusted forwarding metadata")
type contextKey struct{}
// Metadata is the normalized request identity shared by downstream packages.
type Metadata struct {
RequestID string
ClientIP netip.Addr
ClientIPSource string
ProxyPeerIP netip.Addr
ForwardedFor string
Scheme string
Host string
}
// Config chooses the only peers whose forwarding metadata may affect identity.
type Config struct {
TrustedProxies []netip.Prefix
Random io.Reader
RequestIDBytes int
}
// Resolver is immutable and safe for concurrent use when Random is.
type Resolver struct {
trusted []netip.Prefix
random io.Reader
idBytes int
}
func New(config Config) (*Resolver, error) {
if config.RequestIDBytes == 0 {
config.RequestIDBytes = 16
}
if config.RequestIDBytes < 12 || config.RequestIDBytes > 32 {
return nil, errors.New("requestmeta: request ID entropy must be 12 to 32 bytes")
}
if config.Random == nil {
config.Random = rand.Reader
}
trusted := make([]netip.Prefix, len(config.TrustedProxies))
for i, prefix := range config.TrustedProxies {
if !prefix.IsValid() {
return nil, fmt.Errorf("requestmeta: trusted proxy %d is invalid", i)
}
trusted[i] = prefix.Masked()
}
return &Resolver{trusted: trusted, random: config.Random, idBytes: config.RequestIDBytes}, nil
}
// Middleware fails closed before application code when entropy or trusted
// forwarding metadata is invalid.
func (resolver *Resolver) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
metadata, err := resolver.Resolve(request)
if err != nil {
response.Header().Set("Cache-Control", "no-store")
status := http.StatusServiceUnavailable
message := "request metadata unavailable"
if errors.Is(err, ErrInvalidForwarding) {
status = http.StatusBadRequest
message = "invalid forwarding metadata"
}
http.Error(response, message, status)
return
}
response.Header().Set("X-Request-ID", metadata.RequestID)
next.ServeHTTP(response, request.WithContext(context.WithValue(request.Context(), contextKey{}, metadata)))
})
}
// FromContext returns metadata installed by Middleware.
func FromContext(ctx context.Context) (Metadata, bool) {
metadata, ok := ctx.Value(contextKey{}).(Metadata)
return metadata, ok
}
func (resolver *Resolver) Resolve(request *http.Request) (Metadata, error) {
requestID, err := resolver.requestID()
if err != nil {
return Metadata{}, fmt.Errorf("requestmeta: generate request ID: %w", err)
}
peer, err := peerAddress(request.RemoteAddr)
if err != nil {
return Metadata{}, err
}
if !validAuthority(request.Host) {
return Metadata{}, ErrInvalidForwarding
}
metadata := Metadata{RequestID: requestID, ClientIP: peer, ClientIPSource: "peer", ProxyPeerIP: peer, Host: request.Host, Scheme: "http"}
if request.TLS != nil {
metadata.Scheme = "https"
}
if !resolver.isTrusted(peer) {
return metadata, nil
}
forwardedFor := strings.Join(request.Header.Values("X-Forwarded-For"), ",")
forwardedProto, protoOK := uniqueHeader(request.Header, "X-Forwarded-Proto")
forwardedHost, hostOK := uniqueHeader(request.Header, "X-Forwarded-Host")
if !protoOK || !hostOK {
return Metadata{}, ErrInvalidForwarding
}
if len(forwardedFor) > maxForwardedHeader || len(forwardedProto) > 64 || len(forwardedHost) > 1024 {
return Metadata{}, ErrInvalidForwarding
}
if forwardedFor != "" {
chain, err := parseForwardedFor(forwardedFor)
if err != nil {
return Metadata{}, err
}
candidate := peer
for index := len(chain) - 1; index >= 0 && resolver.isTrusted(candidate); index-- {
candidate = chain[index]
}
metadata.ClientIP = candidate
metadata.ClientIPSource = "forwarded"
metadata.ForwardedFor = forwardedFor
}
if forwardedProto != "" {
value, ok := singleForwardedValue(forwardedProto)
if !ok || (value != "http" && value != "https") {
return Metadata{}, ErrInvalidForwarding
}
metadata.Scheme = value
}
if forwardedHost != "" {
value, ok := singleForwardedValue(forwardedHost)
if !ok || !validAuthority(value) {
return Metadata{}, ErrInvalidForwarding
}
metadata.Host = value
}
return metadata, nil
}
func (resolver *Resolver) requestID() (string, error) {
value := make([]byte, resolver.idBytes)
if _, err := io.ReadFull(resolver.random, value); err != nil {
return "", err
}
return hex.EncodeToString(value), nil
}
func (resolver *Resolver) isTrusted(address netip.Addr) bool {
for _, prefix := range resolver.trusted {
if prefix.Contains(address) {
return true
}
}
return false
}
func peerAddress(remote string) (netip.Addr, error) {
host, _, err := net.SplitHostPort(remote)
if err != nil {
return netip.Addr{}, errors.New("requestmeta: remote address must contain host and port")
}
address, err := netip.ParseAddr(host)
if err != nil {
return netip.Addr{}, errors.New("requestmeta: remote address is invalid")
}
return address.Unmap(), nil
}
func parseForwardedFor(value string) ([]netip.Addr, error) {
parts := strings.Split(value, ",")
if len(parts) == 0 || len(parts) > 32 {
return nil, ErrInvalidForwarding
}
result := make([]netip.Addr, 0, len(parts))
for _, part := range parts {
address, err := netip.ParseAddr(strings.TrimSpace(part))
if err != nil {
return nil, ErrInvalidForwarding
}
result = append(result, address.Unmap())
}
return result, nil
}
func singleForwardedValue(value string) (string, bool) {
parts := strings.Split(value, ",")
if len(parts) != 1 {
return "", false
}
trimmed := strings.ToLower(strings.TrimSpace(parts[0]))
return trimmed, trimmed != ""
}
func uniqueHeader(header http.Header, name string) (string, bool) {
values := header.Values(name)
if len(values) > 1 {
return "", false
}
if len(values) == 0 {
return "", true
}
return values[0], true
}
func validAuthority(value string) bool {
return value != "" && len(value) <= 1024 && !strings.ContainsAny(value, "\\/\x00\r\n\t ,")
}