mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-06-16 20:08:59 -04:00
Merge branch 'origin/main' into 'next-release/main'
This commit is contained in:
2
go.mod
2
go.mod
@@ -20,7 +20,7 @@ require (
|
||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||
github.com/gabriel-vasile/mimetype v1.4.13
|
||||
github.com/ggwhite/go-masker v1.1.0
|
||||
github.com/go-chi/chi/v5 v5.2.5
|
||||
github.com/go-chi/chi/v5 v5.3.0
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/go-jose/go-jose/v3 v3.0.5
|
||||
github.com/go-ldap/ldap/v3 v3.4.13
|
||||
|
||||
4
go.sum
4
go.sum
@@ -375,8 +375,8 @@ github.com/go-asn1-ber/asn1-ber v1.4.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
|
||||
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
|
||||
github.com/go-chi/chi/v5 v5.3.0 h1:halUjDxhshgXHMrao5bB8eNBXo/rnzwr8m5m36glehM=
|
||||
github.com/go-chi/chi/v5 v5.3.0/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||
|
||||
70
vendor/github.com/go-chi/chi/v5/README.md
generated
vendored
70
vendor/github.com/go-chi/chi/v5/README.md
generated
vendored
@@ -87,7 +87,7 @@ func main() {
|
||||
|
||||
// A good base middleware stack
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(middleware.RealIP)
|
||||
r.Use(middleware.ClientIPFromRemoteAddr) // pick one ClientIPFrom* based on your infra, see below
|
||||
r.Use(middleware.Logger)
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
@@ -349,7 +349,11 @@ with `net/http` can be used with chi's mux.
|
||||
| [Logger] | Logs the start and end of each request with the elapsed processing time |
|
||||
| [NoCache] | Sets response headers to prevent clients from caching |
|
||||
| [Profiler] | Easily attach net/http/pprof to your routers |
|
||||
| [RealIP] | Sets a http.Request's RemoteAddr to either X-Real-IP or X-Forwarded-For |
|
||||
| [ClientIPFromHeader] | Capture client IP from a trusted single-IP header (X-Real-IP, CF-Connecting-IP, ...) |
|
||||
| [ClientIPFromXFF] | Capture client IP from X-Forwarded-For, skipping listed trusted CIDR prefixes |
|
||||
| [ClientIPFromXFFTrustedProxies] | Capture client IP from X-Forwarded-For given a fixed number of trusted proxies |
|
||||
| [ClientIPFromRemoteAddr] | Capture client IP from the TCP RemoteAddr (server directly on the public internet) |
|
||||
| [RealIP] | Deprecated — vulnerable to IP spoofing; use [ClientIPFromXFF] or another ClientIPFrom\* middleware |
|
||||
| [Recoverer] | Gracefully absorb panics and prints the stack trace |
|
||||
| [RequestID] | Injects a request ID into the context of each request |
|
||||
| [RedirectSlashes] | Redirect slashes on routing paths |
|
||||
@@ -375,6 +379,12 @@ with `net/http` can be used with chi's mux.
|
||||
[Logger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Logger
|
||||
[NoCache]: https://pkg.go.dev/github.com/go-chi/chi/middleware#NoCache
|
||||
[Profiler]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Profiler
|
||||
[ClientIPFromHeader]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ClientIPFromHeader
|
||||
[ClientIPFromXFF]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ClientIPFromXFF
|
||||
[ClientIPFromXFFTrustedProxies]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ClientIPFromXFFTrustedProxies
|
||||
[ClientIPFromRemoteAddr]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ClientIPFromRemoteAddr
|
||||
[GetClientIP]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetClientIP
|
||||
[GetClientIPAddr]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetClientIPAddr
|
||||
[RealIP]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RealIP
|
||||
[Recoverer]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Recoverer
|
||||
[RedirectSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RedirectSlashes
|
||||
@@ -402,6 +412,62 @@ with `net/http` can be used with chi's mux.
|
||||
[ThrottleOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleOpts
|
||||
[WrapResponseWriter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WrapResponseWriter
|
||||
|
||||
### Choosing a ClientIP middleware
|
||||
|
||||
The legacy [RealIP] middleware is deprecated — it is vulnerable to IP spoofing
|
||||
(GHSA-3fxj-6jh8-hvhx, GHSA-rjr7-jggh-pgcp, GHSA-9g5q-2w5x-hmxf) and mutates
|
||||
`r.RemoteAddr`. Use one of the four `ClientIPFrom*` middlewares instead — pick
|
||||
exactly one based on your network setup — and read the resulting IP with
|
||||
[GetClientIP] (string) or [GetClientIPAddr] (`netip.Addr`):
|
||||
|
||||
| Your setup | Use |
|
||||
|---|---|
|
||||
| Directly on the public internet, no proxy | `middleware.ClientIPFromRemoteAddr` |
|
||||
| Behind nginx (`X-Real-IP`), Cloudflare (`CF-Connecting-IP`), Apache (`X-Client-IP`) | `middleware.ClientIPFromHeader("<your-trusted-header>")` |
|
||||
| Behind one or more proxies whose IP ranges you can list | `middleware.ClientIPFromXFF("10.0.0.0/8", ...)` |
|
||||
| Behind a known, fixed number of proxies with dynamic IPs | `middleware.ClientIPFromXFFTrustedProxies(2)` |
|
||||
|
||||
```go
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.RequestID)
|
||||
|
||||
// Pick exactly one. Examples for common deployments:
|
||||
|
||||
// Direct internet exposure (no proxy):
|
||||
// r.Use(middleware.ClientIPFromRemoteAddr)
|
||||
|
||||
// Behind Cloudflare:
|
||||
// r.Use(middleware.ClientIPFromHeader("CF-Connecting-IP"))
|
||||
|
||||
// Behind AWS CloudFront (or any proxy fleet with known CIDRs):
|
||||
r.Use(middleware.ClientIPFromXFF(
|
||||
"13.32.0.0/15", // CloudFront IPv4
|
||||
"52.46.0.0/18", // CloudFront IPv4
|
||||
"2600:9000::/28", // CloudFront IPv6
|
||||
))
|
||||
|
||||
// Behind a known number of proxies with dynamic IPs:
|
||||
// r.Use(middleware.ClientIPFromXFFTrustedProxies(2))
|
||||
|
||||
r.Use(middleware.Logger)
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
clientIP := middleware.GetClientIP(r.Context()) // for logs, rate-limit keys, etc.
|
||||
_ = clientIP
|
||||
})
|
||||
```
|
||||
|
||||
These middlewares never mutate `r.RemoteAddr`. They store a normalized
|
||||
`netip.Addr` in the request context — IPv4-mapped IPv6 (`::ffff:a.b.c.d`)
|
||||
is folded to plain IPv4, and IPv6 zone identifiers carried in headers are
|
||||
stripped, so one logical client maps to a single canonical key for logs,
|
||||
rate limits, and ACLs.
|
||||
|
||||
See the per-function godoc for the full semantics of each middleware, and
|
||||
[adam-p's "The perils of the 'real' client IP"](https://adam-p.ca/blog/2022/03/x-forwarded-for/)
|
||||
for the underlying threat model.
|
||||
|
||||
### Extra middlewares & packages
|
||||
|
||||
Please see https://github.com/go-chi for additional packages.
|
||||
|
||||
2
vendor/github.com/go-chi/chi/v5/chi.go
generated
vendored
2
vendor/github.com/go-chi/chi/v5/chi.go
generated
vendored
@@ -77,7 +77,7 @@ type Router interface {
|
||||
// path, with a fresh middleware stack for the inline-Router.
|
||||
Group(fn func(r Router)) Router
|
||||
|
||||
// Route mounts a sub-Router along a `pattern`` string.
|
||||
// Route mounts a sub-Router along a `pattern` string.
|
||||
Route(pattern string, fn func(r Router)) Router
|
||||
|
||||
// Mount attaches another http.Handler along ./pattern/*
|
||||
|
||||
263
vendor/github.com/go-chi/chi/v5/middleware/client_ip.go
generated
vendored
Normal file
263
vendor/github.com/go-chi/chi/v5/middleware/client_ip.go
generated
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// clientIPCtxKey stores the client IP set by any of the ClientIPFrom* middlewares.
|
||||
var clientIPCtxKey = &contextKey{"clientIP"}
|
||||
|
||||
// xForwardedForHeader is the canonical form of the X-Forwarded-For header
|
||||
// name, used by the XFF-based middlewares.
|
||||
const xForwardedForHeader = "X-Forwarded-For"
|
||||
|
||||
// ClientIPFromHeader stores the client IP from a single-IP header set by
|
||||
// your reverse proxy. Read it with [GetClientIP].
|
||||
//
|
||||
// Only safe with headers your proxy unconditionally OVERWRITES on every
|
||||
// request, e.g.:
|
||||
//
|
||||
// - X-Real-IP — Nginx with ngx_http_realip_module
|
||||
// - X-Client-IP — Apache with mod_remoteip
|
||||
// - CF-Connecting-IP — Cloudflare
|
||||
//
|
||||
// True-Client-IP, X-Azure-ClientIP, and Fastly-Client-IP look similar but
|
||||
// pass through from the client by default in those products; don't use them
|
||||
// unless your edge strips the inbound value.
|
||||
//
|
||||
// If the header reaches us with multiple values (misconfigured proxy that
|
||||
// appends, or a downstream proxy not stripping a client-supplied value),
|
||||
// the LAST value wins — that's the one set by the hop closest to us, and
|
||||
// therefore the most trusted. Fail-closed if the last value doesn't parse:
|
||||
// no client IP is set rather than falling back to earlier (less-trusted)
|
||||
// values.
|
||||
//
|
||||
// v4-mapped IPv6 (::ffff:a.b.c.d) folds to plain v4 and IPv6 zones are
|
||||
// stripped before storage.
|
||||
func ClientIPFromHeader(trustedHeader string) func(http.Handler) http.Handler {
|
||||
header := http.CanonicalHeaderKey(trustedHeader)
|
||||
return func(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
values := r.Header.Values(header)
|
||||
if len(values) > 0 {
|
||||
if ip, ok := parseHeaderAddr(values[len(values)-1]); ok {
|
||||
r = r.WithContext(context.WithValue(r.Context(), clientIPCtxKey, ip))
|
||||
}
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ClientIPFromXFF stores the client IP read from the X-Forwarded-For header,
|
||||
// walking the chain right-to-left and skipping any IP that falls within one
|
||||
// of the given trusted CIDR prefixes. The first IP that is not trusted is
|
||||
// the client. Read it with [GetClientIP].
|
||||
//
|
||||
// An unparseable entry mid-chain aborts the walk and leaves no client IP
|
||||
// set (fail-closed) — we can't safely trust anything left of garbage.
|
||||
//
|
||||
// Use this when you sit behind one or more reverse proxies whose IP ranges
|
||||
// you can enumerate as CIDRs:
|
||||
//
|
||||
// r.Use(middleware.ClientIPFromXFF(
|
||||
// "13.32.0.0/15", // CloudFront IPv4
|
||||
// "52.46.0.0/18", // CloudFront IPv4
|
||||
// "2600:9000::/28", // CloudFront IPv6
|
||||
// ))
|
||||
//
|
||||
// Calling with no arguments returns the rightmost XFF entry, or no IP if
|
||||
// that entry doesn't parse (fail-closed) — safe only if you have exactly
|
||||
// one trusted hop directly in front of this server (e.g., nginx on localhost).
|
||||
//
|
||||
// v4-mapped IPv6 (::ffff:a.b.c.d) folds to plain v4 and IPv6 zones are
|
||||
// stripped before the prefix check and storage; otherwise an attacker
|
||||
// could use either notation to alias a trusted IP past the check.
|
||||
//
|
||||
// If you know the number of trusted proxies but not their IPs, use
|
||||
// [ClientIPFromXFFTrustedProxies] instead.
|
||||
//
|
||||
// Panics at startup if any prefix is invalid.
|
||||
func ClientIPFromXFF(trustedIPPrefixes ...string) func(http.Handler) http.Handler {
|
||||
prefixes := make([]netip.Prefix, len(trustedIPPrefixes))
|
||||
for i, p := range trustedIPPrefixes {
|
||||
prefixes[i] = netip.MustParsePrefix(p)
|
||||
}
|
||||
return func(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var found netip.Addr
|
||||
walkXFF(r.Header[xForwardedForHeader], func(v string) bool {
|
||||
ip, ok := parseHeaderAddr(v)
|
||||
if !ok {
|
||||
return true // fail-closed; leave found unset
|
||||
}
|
||||
if inAnyPrefix(ip, prefixes) {
|
||||
return false // trusted hop; keep walking left
|
||||
}
|
||||
found = ip
|
||||
return true
|
||||
})
|
||||
if found.IsValid() {
|
||||
r = r.WithContext(context.WithValue(r.Context(), clientIPCtxKey, found))
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ClientIPFromXFFTrustedProxies stores the client IP read from the
|
||||
// X-Forwarded-For header, given the exact number of trusted reverse proxies
|
||||
// between this server and the public internet. It returns the IP at position
|
||||
// len(xff) - numTrustedProxies in the merged X-Forwarded-For list — the IP
|
||||
// added by the outermost of your trusted proxies, the only IP in the chain
|
||||
// that none of your proxies have allowed an attacker to forge. Read it with
|
||||
// [GetClientIP].
|
||||
//
|
||||
// Use this when:
|
||||
// - You know exactly how many proxies you sit behind, AND
|
||||
// - Their IP addresses are dynamic (autoscaling proxy pools, ephemeral
|
||||
// containers, dynamic CDN edges) so listing CIDRs with [ClientIPFromXFF]
|
||||
// is impractical.
|
||||
//
|
||||
// WARNING: This variant is brittle to network architecture changes. If you
|
||||
// add or remove a proxy level, numTrustedProxies silently becomes wrong and
|
||||
// you may start trusting an attacker-supplied IP. Prefer [ClientIPFromXFF]
|
||||
// with explicit trusted CIDRs whenever you can.
|
||||
//
|
||||
// If the XFF chain has fewer than numTrustedProxies entries (header missing
|
||||
// or architecture changed), no client IP is set and [GetClientIP] returns "".
|
||||
//
|
||||
// Like [ClientIPFromXFF], v4-mapped IPv6 folds to plain v4 and IPv6 zones
|
||||
// are stripped before storage.
|
||||
//
|
||||
// Panics at startup if numTrustedProxies < 1.
|
||||
func ClientIPFromXFFTrustedProxies(numTrustedProxies int) func(http.Handler) http.Handler {
|
||||
if numTrustedProxies < 1 {
|
||||
panic("middleware.ClientIPFromXFFTrustedProxies: numTrustedProxies must be >= 1")
|
||||
}
|
||||
return func(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
n := numTrustedProxies
|
||||
var entry string
|
||||
walkXFF(r.Header[xForwardedForHeader], func(v string) bool {
|
||||
n--
|
||||
if n == 0 {
|
||||
entry = v
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if entry != "" {
|
||||
if ip, ok := parseHeaderAddr(entry); ok {
|
||||
r = r.WithContext(context.WithValue(r.Context(), clientIPCtxKey, ip))
|
||||
}
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ClientIPFromRemoteAddr stores the client IP read from the TCP RemoteAddr
|
||||
// of the incoming request — the IP address of whoever opened the connection
|
||||
// to this server. Read it with [GetClientIP].
|
||||
//
|
||||
// Use this when this server is directly connected to the public internet
|
||||
// with NO reverse proxy in front of it. Behind a reverse proxy, RemoteAddr
|
||||
// is the proxy's IP, not the client's — use [ClientIPFromHeader] or
|
||||
// [ClientIPFromXFF] instead.
|
||||
//
|
||||
// IPv4 clients on a dual-stack listener surface as ::ffff:a.b.c.d; they
|
||||
// fold to plain v4 before storage so one logical client maps to one key.
|
||||
// IPv6 zones are preserved (link-local connections may legitimately have one).
|
||||
func ClientIPFromRemoteAddr(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
host = r.RemoteAddr // RemoteAddr may already be a bare IP (e.g. in tests).
|
||||
}
|
||||
if ip, err := netip.ParseAddr(host); err == nil {
|
||||
r = r.WithContext(context.WithValue(r.Context(), clientIPCtxKey, ip.Unmap()))
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// GetClientIP returns the client IP as a string, as set by one of the
|
||||
// ClientIPFrom* middlewares. Returns "" if no valid IP was set.
|
||||
// Convenient for logging, rate-limit keys, etc.
|
||||
func GetClientIP(ctx context.Context) string {
|
||||
ip := GetClientIPAddr(ctx)
|
||||
if !ip.IsValid() {
|
||||
return ""
|
||||
}
|
||||
return ip.String()
|
||||
}
|
||||
|
||||
// GetClientIPAddr returns the client IP as a [netip.Addr], as set by one of
|
||||
// the ClientIPFrom* middlewares. The returned Addr is the zero value if not
|
||||
// set; use [netip.Addr.IsValid] to check. Useful when you need typed work —
|
||||
// prefix containment, Is4/Is6, etc. — without re-parsing the string.
|
||||
func GetClientIPAddr(ctx context.Context) netip.Addr {
|
||||
ip, _ := ctx.Value(clientIPCtxKey).(netip.Addr)
|
||||
return ip
|
||||
}
|
||||
|
||||
// walkXFF walks the entries of the merged X-Forwarded-For chain
|
||||
// RIGHT-TO-LEFT, invoking visit on each trimmed non-empty entry. visit
|
||||
// returns true to stop the walk. Lazy walk, zero allocations (entries
|
||||
// are substrings of the input headers).
|
||||
//
|
||||
// Multiple XFF headers are merged per RFC 2616 — each header's
|
||||
// comma-separated entries in order received — so an attacker cannot pick
|
||||
// which value security logic sees by sending a duplicate header.
|
||||
func walkXFF(headers []string, visit func(entry string) bool) {
|
||||
for hi := len(headers) - 1; hi >= 0; hi-- {
|
||||
h := headers[hi]
|
||||
for h != "" {
|
||||
var v string
|
||||
if i := strings.LastIndexByte(h, ','); i >= 0 {
|
||||
v, h = h[i+1:], h[:i]
|
||||
} else {
|
||||
v, h = h, ""
|
||||
}
|
||||
v = strings.TrimSpace(v)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if visit(v) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// inAnyPrefix reports whether ip falls within any of the given prefixes.
|
||||
func inAnyPrefix(ip netip.Addr, prefixes []netip.Prefix) bool {
|
||||
for _, p := range prefixes {
|
||||
if p.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parseHeaderAddr parses s and normalizes for storage: v4-mapped IPv6
|
||||
// (::ffff:a.b.c.d) folds to plain v4, IPv6 zone is stripped. Both defend the
|
||||
// trust-prefix check against attacker-injected aliases — [netip.Prefix.Contains]
|
||||
// returns false for v4-mapped addresses vs v4 prefixes and for any zoned
|
||||
// address, so without folding/stripping an attacker could escape an
|
||||
// otherwise valid trust list.
|
||||
//
|
||||
// Header-sourced IPs only. [ClientIPFromRemoteAddr] normalizes inline
|
||||
// (Unmap, but zone preserved for legitimate link-local connections).
|
||||
func parseHeaderAddr(s string) (netip.Addr, bool) {
|
||||
ip, err := netip.ParseAddr(s)
|
||||
if err != nil {
|
||||
return netip.Addr{}, false
|
||||
}
|
||||
return ip.Unmap().WithZone(""), true
|
||||
}
|
||||
4
vendor/github.com/go-chi/chi/v5/middleware/compress.go
generated
vendored
4
vendor/github.com/go-chi/chi/v5/middleware/compress.go
generated
vendored
@@ -70,8 +70,8 @@ func NewCompressor(level int, types ...string) *Compressor {
|
||||
if strings.Contains(strings.TrimSuffix(t, "/*"), "*") {
|
||||
panic(fmt.Sprintf("middleware/compress: Unsupported content-type wildcard pattern '%s'. Only '/*' supported", t))
|
||||
}
|
||||
if strings.HasSuffix(t, "/*") {
|
||||
allowedWildcards[strings.TrimSuffix(t, "/*")] = struct{}{}
|
||||
if before, ok := strings.CutSuffix(t, "/*"); ok {
|
||||
allowedWildcards[before] = struct{}{}
|
||||
} else {
|
||||
allowedTypes[t] = struct{}{}
|
||||
}
|
||||
|
||||
10
vendor/github.com/go-chi/chi/v5/middleware/logger.go
generated
vendored
10
vendor/github.com/go-chi/chi/v5/middleware/logger.go
generated
vendored
@@ -96,6 +96,8 @@ type DefaultLogFormatter struct {
|
||||
|
||||
// NewLogEntry creates a new LogEntry for the request.
|
||||
func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry {
|
||||
ctx := r.Context()
|
||||
|
||||
useColor := !l.NoColor
|
||||
entry := &defaultLogEntry{
|
||||
DefaultLogFormatter: l,
|
||||
@@ -104,7 +106,7 @@ func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry {
|
||||
useColor: useColor,
|
||||
}
|
||||
|
||||
reqID := GetReqID(r.Context())
|
||||
reqID := GetReqID(ctx)
|
||||
if reqID != "" {
|
||||
cW(entry.buf, useColor, nYellow, "[%s] ", reqID)
|
||||
}
|
||||
@@ -118,7 +120,11 @@ func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry {
|
||||
cW(entry.buf, useColor, nCyan, "%s://%s%s %s\" ", scheme, r.Host, r.RequestURI, r.Proto)
|
||||
|
||||
entry.buf.WriteString("from ")
|
||||
entry.buf.WriteString(r.RemoteAddr)
|
||||
clientIP := GetClientIP(ctx)
|
||||
if clientIP == "" {
|
||||
clientIP = r.RemoteAddr
|
||||
}
|
||||
entry.buf.WriteString(clientIP)
|
||||
entry.buf.WriteString(" - ")
|
||||
|
||||
return entry
|
||||
|
||||
17
vendor/github.com/go-chi/chi/v5/middleware/realip.go
generated
vendored
17
vendor/github.com/go-chi/chi/v5/middleware/realip.go
generated
vendored
@@ -17,17 +17,14 @@ var xRealIP = http.CanonicalHeaderKey("X-Real-IP")
|
||||
// of parsing either the True-Client-IP, X-Real-IP or the X-Forwarded-For headers
|
||||
// (in that order).
|
||||
//
|
||||
// This middleware should be inserted fairly early in the middleware stack to
|
||||
// ensure that subsequent layers (e.g., request loggers) which examine the
|
||||
// RemoteAddr will see the intended value.
|
||||
// Deprecated: RealIP is vulnerable to IP spoofing — it mutates r.RemoteAddr
|
||||
// to the leftmost X-Forwarded-For value, or to True-Client-IP / X-Real-IP
|
||||
// whether or not your infrastructure actually sets them. See
|
||||
// GHSA-3fxj-6jh8-hvhx, GHSA-rjr7-jggh-pgcp, GHSA-9g5q-2w5x-hmxf.
|
||||
//
|
||||
// You should only use this middleware if you can trust the headers passed to
|
||||
// you (in particular, the three headers this middleware uses), for example
|
||||
// because you have placed a reverse proxy like HAProxy or nginx in front of
|
||||
// chi. If your reverse proxies are configured to pass along arbitrary header
|
||||
// values from the client, or if you use this middleware without a reverse
|
||||
// proxy, malicious clients will be able to make you very sad (or, depending on
|
||||
// how you're using RemoteAddr, vulnerable to an attack of some sort).
|
||||
// Use [ClientIPFromHeader], [ClientIPFromXFF], [ClientIPFromXFFTrustedProxies]
|
||||
// or [ClientIPFromRemoteAddr] and read the IP with [GetClientIP] instead.
|
||||
// These never mutate r.RemoteAddr.
|
||||
func RealIP(h http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
if rip := realIP(r); rip != "" {
|
||||
|
||||
4
vendor/github.com/go-chi/chi/v5/middleware/wrap_writer.go
generated
vendored
4
vendor/github.com/go-chi/chi/v5/middleware/wrap_writer.go
generated
vendored
@@ -208,8 +208,10 @@ func (f *http2FancyWriter) Push(target string, opts *http.PushOptions) error {
|
||||
|
||||
func (f *httpFancyWriter) ReadFrom(r io.Reader) (int64, error) {
|
||||
if f.basicWriter.tee != nil {
|
||||
// Route through basicWriter.Write so that data is also written to the
|
||||
// tee writer. basicWriter.Write already increments basicWriter.bytes,
|
||||
// so we must NOT add n again here (that would double-count).
|
||||
n, err := io.Copy(&f.basicWriter, r)
|
||||
f.basicWriter.bytes += int(n)
|
||||
return n, err
|
||||
}
|
||||
rf := f.basicWriter.ResponseWriter.(io.ReaderFrom)
|
||||
|
||||
4
vendor/github.com/go-chi/chi/v5/mux.go
generated
vendored
4
vendor/github.com/go-chi/chi/v5/mux.go
generated
vendored
@@ -472,9 +472,7 @@ func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
value := rctx.URLParams.Values[i]
|
||||
r.SetPathValue(key, value)
|
||||
}
|
||||
if supportsPattern {
|
||||
setPattern(rctx, r)
|
||||
}
|
||||
r.Pattern = rctx.RoutePattern()
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
|
||||
16
vendor/github.com/go-chi/chi/v5/pattern.go
generated
vendored
16
vendor/github.com/go-chi/chi/v5/pattern.go
generated
vendored
@@ -1,16 +0,0 @@
|
||||
//go:build go1.23 && !tinygo
|
||||
// +build go1.23,!tinygo
|
||||
|
||||
package chi
|
||||
|
||||
import "net/http"
|
||||
|
||||
// supportsPattern is true if the Go version is 1.23 and above.
|
||||
//
|
||||
// If this is true, `net/http.Request` has field `Pattern`.
|
||||
const supportsPattern = true
|
||||
|
||||
// setPattern sets the mux matched pattern in the http Request.
|
||||
func setPattern(rctx *Context, r *http.Request) {
|
||||
r.Pattern = rctx.routePattern
|
||||
}
|
||||
17
vendor/github.com/go-chi/chi/v5/pattern_fallback.go
generated
vendored
17
vendor/github.com/go-chi/chi/v5/pattern_fallback.go
generated
vendored
@@ -1,17 +0,0 @@
|
||||
//go:build !go1.23 || tinygo
|
||||
// +build !go1.23 tinygo
|
||||
|
||||
package chi
|
||||
|
||||
import "net/http"
|
||||
|
||||
// supportsPattern is true if the Go version is 1.23 and above.
|
||||
//
|
||||
// If this is true, `net/http.Request` has field `Pattern`.
|
||||
const supportsPattern = false
|
||||
|
||||
// setPattern sets the mux matched pattern in the http Request.
|
||||
//
|
||||
// setPattern is only supported in Go 1.23 and above so
|
||||
// this is just a blank function so that it compiles.
|
||||
func setPattern(rctx *Context, r *http.Request) {}
|
||||
13
vendor/github.com/go-chi/chi/v5/tree.go
generated
vendored
13
vendor/github.com/go-chi/chi/v5/tree.go
generated
vendored
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -836,11 +837,15 @@ func Walk(r Routes, walkFn WalkFunc) error {
|
||||
|
||||
func walk(r Routes, walkFn WalkFunc, parentRoute string, parentMw ...func(http.Handler) http.Handler) error {
|
||||
for _, route := range r.Routes() {
|
||||
mws := make([]func(http.Handler) http.Handler, len(parentMw))
|
||||
copy(mws, parentMw)
|
||||
mws = append(mws, r.Middlewares()...)
|
||||
mws := slices.Concat(parentMw, r.Middlewares())
|
||||
|
||||
if route.SubRoutes != nil {
|
||||
if handler, ok := route.Handlers["*"]; ok {
|
||||
if chain, ok := handler.(*ChainHandler); ok {
|
||||
mws = append(mws, chain.Middlewares...)
|
||||
}
|
||||
}
|
||||
|
||||
if err := walk(route.SubRoutes, walkFn, parentRoute+route.Pattern, mws...); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -854,7 +859,7 @@ func walk(r Routes, walkFn WalkFunc, parentRoute string, parentMw ...func(http.H
|
||||
}
|
||||
|
||||
fullRoute := parentRoute + route.Pattern
|
||||
fullRoute = strings.Replace(fullRoute, "/*/", "/", -1)
|
||||
fullRoute = strings.ReplaceAll(fullRoute, "/*/", "/")
|
||||
|
||||
if chain, ok := handler.(*ChainHandler); ok {
|
||||
if err := walkFn(method, fullRoute, chain.Endpoint, append(mws, chain.Middlewares...)...); err != nil {
|
||||
|
||||
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@@ -452,8 +452,8 @@ github.com/go-acme/lego/v4/challenge
|
||||
# github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667
|
||||
## explicit; go 1.13
|
||||
github.com/go-asn1-ber/asn1-ber
|
||||
# github.com/go-chi/chi/v5 v5.2.5
|
||||
## explicit; go 1.22
|
||||
# github.com/go-chi/chi/v5 v5.3.0
|
||||
## explicit; go 1.23
|
||||
github.com/go-chi/chi/v5
|
||||
github.com/go-chi/chi/v5/middleware
|
||||
# github.com/go-chi/render v1.0.3
|
||||
|
||||
Reference in New Issue
Block a user