diff --git a/server/go.mod b/server/go.mod index ecfccd2..9f0dda1 100644 --- a/server/go.mod +++ b/server/go.mod @@ -3,7 +3,7 @@ module github.com/nimzshafie/airgap-devkit/server go 1.26.6 require ( - github.com/go-chi/chi/v5 v5.3.2 + github.com/go-chi/chi/v5 v5.5.0 golang.org/x/text v0.41.0 ) diff --git a/server/go.sum b/server/go.sum index 1458bdc..ab67dcb 100644 --- a/server/go.sum +++ b/server/go.sum @@ -2,8 +2,8 @@ github.com/Acconut/go-httptest-recorder v1.0.0 h1:TAv2dfnqp/l+SUvIaMAUK4GeN4+wqb github.com/Acconut/go-httptest-recorder v1.0.0/go.mod h1:CwQyhTH1kq/gLyWiRieo7c0uokpu3PXeyF/nZjUNtmM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY= -github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto= +github.com/go-chi/chi/v5 v5.5.0 h1:xdKQ1dJmVJsmgahrXSKhUx8NyVPzpwdlyrrQFpMPJgg= +github.com/go-chi/chi/v5 v5.5.0/go.mod h1:d1IG7GtKPSjPyBP365PH8sAGVHk3qfB/IhjFNRH1wWM= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= diff --git a/server/vendor/github.com/go-chi/chi/v5/README.md b/server/vendor/github.com/go-chi/chi/v5/README.md index 07aeaa8..0d8886f 100644 --- a/server/vendor/github.com/go-chi/chi/v5/README.md +++ b/server/vendor/github.com/go-chi/chi/v5/README.md @@ -345,6 +345,7 @@ with `net/http` can be used with chi's mux. | [Compress] | Gzip compression for clients that accept compressed responses | | [ContentCharset] | Ensure charset for Content-Type request headers | | [CleanPath] | Clean double slashes from request path | +| [Deprecation] | Set the Deprecation response header (RFC 9745); see also [Sunset] | | [GetHead] | Automatically route undefined HEAD requests to GET handlers | | [Heartbeat] | Monitoring endpoint to check the servers pulse | | [Logger] | Logs the start and end of each request with the elapsed processing time | @@ -361,57 +362,58 @@ with `net/http` can be used with chi's mux. | [RouteHeaders] | Route handling for request headers | | [SetHeader] | Short-hand middleware to set a response header key/value | | [StripSlashes] | Strip slashes on routing paths | -| [Sunset] | Sunset set Deprecation/Sunset header to response | +| [Sunset] | Set the Sunset response header (RFC 8594); see also [Deprecation] | | [Throttle] | Puts a ceiling on the number of concurrent requests | | [Timeout] | Signals to the request context when the timeout deadline is reached | | [URLFormat] | Parse extension from url and put it on request context | | [WithValue] | Short-hand middleware to set a key/value on the request context | ---------------------------------------------------------------------------------------------------- -[AllowContentEncoding]: https://pkg.go.dev/github.com/go-chi/chi/middleware#AllowContentEncoding -[AllowContentType]: https://pkg.go.dev/github.com/go-chi/chi/middleware#AllowContentType -[BasicAuth]: https://pkg.go.dev/github.com/go-chi/chi/middleware#BasicAuth -[Compress]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Compress -[ContentCharset]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ContentCharset -[CleanPath]: https://pkg.go.dev/github.com/go-chi/chi/middleware#CleanPath -[GetHead]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetHead -[GetReqID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetReqID -[Heartbeat]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Heartbeat -[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 -[RequestLogger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestLogger -[RequestID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestID -[RouteHeaders]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RouteHeaders -[SetHeader]: https://pkg.go.dev/github.com/go-chi/chi/middleware#SetHeader -[StripSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#StripSlashes +[AllowContentEncoding]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#AllowContentEncoding +[AllowContentType]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#AllowContentType +[BasicAuth]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#BasicAuth +[Compress]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Compress +[ContentCharset]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#ContentCharset +[CleanPath]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#CleanPath +[Deprecation]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Deprecation +[GetHead]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#GetHead +[GetReqID]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#GetReqID +[Heartbeat]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Heartbeat +[Logger]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Logger +[NoCache]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#NoCache +[Profiler]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Profiler +[ClientIPFromHeader]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#ClientIPFromHeader +[ClientIPFromXFF]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#ClientIPFromXFF +[ClientIPFromXFFTrustedProxies]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#ClientIPFromXFFTrustedProxies +[ClientIPFromRemoteAddr]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#ClientIPFromRemoteAddr +[GetClientIP]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#GetClientIP +[GetClientIPAddr]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#GetClientIPAddr +[RealIP]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#RealIP +[Recoverer]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Recoverer +[RedirectSlashes]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#RedirectSlashes +[RequestLogger]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#RequestLogger +[RequestID]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#RequestID +[RouteHeaders]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#RouteHeaders +[SetHeader]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#SetHeader +[StripSlashes]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#StripSlashes [Sunset]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Sunset -[Throttle]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Throttle -[ThrottleBacklog]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleBacklog -[ThrottleWithOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleWithOpts -[Timeout]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Timeout -[URLFormat]: https://pkg.go.dev/github.com/go-chi/chi/middleware#URLFormat -[WithLogEntry]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WithLogEntry -[WithValue]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WithValue -[Compressor]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Compressor -[DefaultLogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#DefaultLogFormatter -[EncoderFunc]: https://pkg.go.dev/github.com/go-chi/chi/middleware#EncoderFunc -[HeaderRoute]: https://pkg.go.dev/github.com/go-chi/chi/middleware#HeaderRoute -[HeaderRouter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#HeaderRouter -[LogEntry]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LogEntry -[LogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LogFormatter -[LoggerInterface]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LoggerInterface -[ThrottleOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleOpts -[WrapResponseWriter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WrapResponseWriter +[Throttle]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Throttle +[ThrottleBacklog]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#ThrottleBacklog +[ThrottleWithOpts]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#ThrottleWithOpts +[Timeout]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Timeout +[URLFormat]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#URLFormat +[WithLogEntry]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#WithLogEntry +[WithValue]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#WithValue +[Compressor]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#Compressor +[DefaultLogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#DefaultLogFormatter +[EncoderFunc]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#EncoderFunc +[HeaderRoute]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#HeaderRoute +[HeaderRouter]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#HeaderRouter +[LogEntry]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#LogEntry +[LogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#LogFormatter +[LoggerInterface]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#LoggerInterface +[ThrottleOpts]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#ThrottleOpts +[WrapResponseWriter]: https://pkg.go.dev/github.com/go-chi/chi/v5/middleware#WrapResponseWriter ### Choosing a ClientIP middleware @@ -474,6 +476,30 @@ 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. +### Deprecating and removing a route + +Use `Deprecation` first. Add `Sunset` when you know the removal date. + +| Situation | Use | +| :------------------------------------------------------- | :-------------------------- | +| Route works, clients should migrate, no removal date yet | `Deprecation` | +| You know the date the route will stop working | `Deprecation` + `Sunset` | +| Route is already removed | Neither. Return `410 Gone`. | + +```go +// A bad date parses to the zero time, and the middleware panics at startup. +deprecatedAt, _ := time.Parse(time.DateOnly, "2026-01-15") +sunsetAt, _ := time.Parse(time.DateOnly, "2026-07-01") + +// Step 1: the route is deprecated. +r.With(middleware.Deprecation(deprecatedAt)).Get("/v1/users", listUsers) + +// Step 2: the removal date is known. +r.With(middleware.Deprecation(deprecatedAt), middleware.Sunset(sunsetAt)).Get("/v1/users", listUsers) + +// After sunsetAt: remove the route, or return 410 Gone. +``` + ### Extra middlewares & packages Please see https://github.com/go-chi for additional packages. diff --git a/server/vendor/github.com/go-chi/chi/v5/chi.go b/server/vendor/github.com/go-chi/chi/v5/chi.go index cb129e3..6911bb5 100644 --- a/server/vendor/github.com/go-chi/chi/v5/chi.go +++ b/server/vendor/github.com/go-chi/chi/v5/chi.go @@ -2,7 +2,7 @@ // // chi supports the four most recent major versions of Go. // -// Example: +// # Example // // package main // @@ -25,11 +25,13 @@ // http.ListenAndServe(":3333", r) // } // -// See github.com/go-chi/chi/_examples/ for more in-depth examples. +// See [github.com/go-chi/chi/v5/_examples] for more in-depth examples. +// +// # URL patterns // // URL patterns allow for easy matching of path components in HTTP // requests. The matching components can then be accessed using -// chi.URLParam(). All patterns must begin with a slash. +// [chi.URLParam](). All patterns must begin with a slash. // // A simple named placeholder {name} matches any sequence of characters // up to the next / or the end of the URL. Trailing slashes on paths must @@ -37,11 +39,11 @@ // // A placeholder with a name followed by a colon allows a regular // expression match, for example {number:\\d+}. The regular expression -// syntax is Go's normal regexp RE2 syntax, except that / will never be -// matched. An anonymous regexp pattern is allowed, using an empty string -// before the colon in the placeholder, such as {:\\d+} +// syntax is Go's normal [regexp] RE2 syntax (see [regexp/syntax]), except +// that / will never be matched. An anonymous regexp pattern is allowed, using +// an empty string before the colon in the placeholder, such as {:\\d+}. // -// The special placeholder of asterisk matches the rest of the requested +// The special placeholder of asterisk (*) matches the rest of the requested // URL. Any trailing characters in the pattern are ignored. This is the only // placeholder which will match / characters. // diff --git a/server/vendor/github.com/go-chi/chi/v5/context.go b/server/vendor/github.com/go-chi/chi/v5/context.go index 8222073..c5c9a74 100644 --- a/server/vendor/github.com/go-chi/chi/v5/context.go +++ b/server/vendor/github.com/go-chi/chi/v5/context.go @@ -3,15 +3,13 @@ package chi import ( "context" "net/http" + "slices" "strings" ) // URLParam returns the url parameter from a http.Request object. func URLParam(r *http.Request, key string) string { - if rctx := RouteContext(r.Context()); rctx != nil { - return rctx.URLParam(key) - } - return "" + return URLParamFromCtx(r.Context(), key) } // URLParamFromCtx returns the url parameter from a http.Request Context. @@ -42,6 +40,8 @@ var ( // Context is the default routing context set on the root node of a // request context to track route patterns, URL parameters and // an optional routing path. +// +// NOTE: New reference fields (slices, maps, pointers) must be deep-copied in Clone. type Context struct { Routes Routes @@ -95,12 +95,36 @@ func (x *Context) Reset() { x.parentCtx = nil } +// Clone a routing context so that it may be used outside of the request/response +// lifecycle, e.g. in a goroutine that outlives the request handler. +// +// Clone must be called before the request handler returns; after that, the +// original context is reset and put back into the pool for reuse by another +// request, racing with the copy. +func (x *Context) Clone() *Context { + clone := *x + + // Detach from the request's context, which is canceled once the request finishes. + clone.parentCtx = nil + + clone.URLParams.Keys = slices.Clone(x.URLParams.Keys) + clone.URLParams.Values = slices.Clone(x.URLParams.Values) + + clone.routeParams.Keys = slices.Clone(x.routeParams.Keys) + clone.routeParams.Values = slices.Clone(x.routeParams.Values) + + clone.RoutePatterns = slices.Clone(x.RoutePatterns) + clone.methodsAllowed = slices.Clone(x.methodsAllowed) + + return &clone +} + // URLParam returns the corresponding URL parameter value from the request // routing context. func (x *Context) URLParam(key string) string { - for k := len(x.URLParams.Keys) - 1; k >= 0; k-- { - if x.URLParams.Keys[k] == key { - return x.URLParams.Values[k] + for i, k := range slices.Backward(x.URLParams.Keys) { + if k == key { + return x.URLParams.Values[i] } } return "" diff --git a/server/vendor/github.com/go-chi/chi/v5/mux.go b/server/vendor/github.com/go-chi/chi/v5/mux.go index 37cd500..7cfc614 100644 --- a/server/vendor/github.com/go-chi/chi/v5/mux.go +++ b/server/vendor/github.com/go-chi/chi/v5/mux.go @@ -51,7 +51,7 @@ type Mux struct { // interface. func NewMux() *Mux { mux := &Mux{tree: &node{}, pool: &sync.Pool{}} - mux.pool.New = func() interface{} { + mux.pool.New = func() any { return NewRouteContext() } return mux @@ -305,6 +305,14 @@ func (mx *Mux) Mount(pattern string, handler http.Handler) { // Assign sub-Router's with the parent not found & method not allowed handler if not specified. subr, ok := handler.(*Mux) + + // Provide runtime safety for ensuring a router isn't mounted onto itself, + // which includes an inline mux derived from it via With()/Group() since + // that shares the same underlying tree. See issue #843. + if ok && subr.tree == mx.tree { + panic(fmt.Sprintf("chi: attempting to Mount() a router onto itself on '%s'", pattern)) + } + if ok && subr.notFoundHandler == nil && mx.notFoundHandler != nil { subr.NotFound(mx.notFoundHandler) } diff --git a/server/vendor/github.com/go-chi/chi/v5/tree.go b/server/vendor/github.com/go-chi/chi/v5/tree.go index e7bc9ed..af4052c 100644 --- a/server/vendor/github.com/go-chi/chi/v5/tree.go +++ b/server/vendor/github.com/go-chi/chi/v5/tree.go @@ -839,8 +839,8 @@ func (ns nodes) Less(i, j int) bool { return ns[i].label < ns[j].label } // tailSort pushes nodes with '/' as the tail to the end of the list for param nodes. // The list order determines the traversal order. func (ns nodes) tailSort() { - for i := len(ns) - 1; i >= 0; i-- { - if ns[i].typ > ntStatic && ns[i].tail == '/' { + for i, n := range slices.Backward(ns) { + if n.typ > ntStatic && n.tail == '/' { ns.Swap(i, len(ns)-1) return } diff --git a/server/vendor/modules.txt b/server/vendor/modules.txt index 8756066..fa5bc5d 100644 --- a/server/vendor/modules.txt +++ b/server/vendor/modules.txt @@ -1,5 +1,5 @@ -# github.com/go-chi/chi/v5 v5.3.2 -## explicit; go 1.23 +# github.com/go-chi/chi/v5 v5.5.0 +## explicit; go 1.24 github.com/go-chi/chi/v5 # github.com/tus/tusd/v2 v2.10.0 ## explicit; go 1.25.8