1985 Commits

Author SHA1 Message Date
yusing
5bf5db1f35 chore(assets): track .min.*; drop **/*.min.* ignore v0.28.1 2026-04-24 15:16:26 +08:00
yusing
c23d440fa0 chore(docker): copy minify scripts into builder stage
Copy scripts/minify into the builder image so containerized builds can
run the minify step. Add the missing final newline to Dockerfile.

Add node_module to docker ignore
2026-04-24 12:00:43 +08:00
yusing
3e8298d1d4 fix(socketproxy): add Transfer-Encoding: chunked header
In goutils commit 5159888197c5a49605495be9b87525fde26c83d1 Copy with an http.ResponseWriter destination no longer flushes after every write unless Content-Type is text/event-stream, or Transfer-Encoding includes chunked without Content-Length.

This causes endpoints like /events not being flushed on write,
which delays notification like container creation/deletion.

This commit enforces flush on every write for socket proxy,
which also applies to agents
2026-04-24 11:47:36 +08:00
yusing
6bb56fea2b chore(deps): downgrade moby client stack and refresh module pins
Downgrade moby API and client requirements, add excludes for newer patch
releases, and bump github.com/yusing/goutils packages plus godoxy agent
and internal/dnsproviders pseudo-versions.
2026-04-24 11:31:27 +08:00
yusing
5699f004c8 refactor(idlewatcher): simplify loading.js console line handling and message fallback
Replace chained level checks with a validLevels list and includes().
Coalesce addConsoleLine call sites. Default missing payload.message to an
empty string so the console does not show undefined.
2026-04-23 17:23:40 +08:00
yusing
e1eb8e9c03 perf(proxmox): cache LXC IPs and avoid interfaces for stopped containers
LXCGetIPsWithStatus reads net config for stopped and suspended guests instead
of the interfaces API. UpdateResources reuses IP lists for 30s when the
resource status is unchanged, caps concurrent LXC IP lookups, and sets
MaxConnsPerHost on the HTTP transport to match.

Add httptest coverage for offline IPs, second-poll IP reuse, and status
transitions. Replace math.Pow session backoff with fixed-duration retries.
2026-04-23 17:23:40 +08:00
yusing
fd299cd265 chore: go mod tidy 2026-04-23 17:23:40 +08:00
yusing
52f372e0a6 chore(submodule): update submodule go-proxmox and go-oidc 2026-04-23 17:23:40 +08:00
yusing
6153e301e3 feat(debug): add debug route for reverseproxy origin unreachable page
Wire GET /reverseproxy/origin_unreachable on the debug mux to
reverseproxy.WriteDebugOriginUnreachablePage for local inspection.
2026-04-23 17:23:39 +08:00
yusing
5dc286f4a9 feat(idlewatcher): restyle loading page and style SSE log levels
Restyle the idle watcher loading UI with design tokens, light and dark
variants via `prefers-color-scheme`, and system font stacks (drop
Google Fonts). Tighten layout, animations, and console presentation.

In `loading.js`, pass event `level` into `addConsoleLine` and apply
`level-*` classes so log lines can reflect debug, info, warn, and
error. On the HTML side, set `color-scheme`, add an empty `alt` on the
logo, and mark the loading dots as `aria-hidden` for assistive
technology.
2026-04-23 17:23:39 +08:00
yusing
01ca378bce chore(debug): bind debug server to 7778 and log startup URL
Listen on :7778 instead of :7777 and emit an info log with the served
URL when the debug HTTP goroutine starts.
2026-04-23 17:23:39 +08:00
yusing
e31cdde636 fix(scripts): harden update-wiki impl doc sync and GitHub line links
When a path includes a line number, use only the #L anchor in the blob URL
and do not append the old #fragment, which duplicated the anchor in the
href.

Ignore READMEs under scripts/ (alongside submodule paths), read a missing
destination mdx as empty, remove unexpected impl .mdx files when syncing, and
run `main` only when `import.meta.main` so the module is importable from
tests. Export `rewriteImplMarkdown` and `syncImplDocs` and add Bun tests for
link rewriting, scripts exclusion, and add/remove mdx output.
2026-04-23 17:23:39 +08:00
yusing
5d9fe5e2fb chore(scripts): set @types/bun to latest in update-wiki
Point devDependency @types/bun at `latest` and refresh `bun.lock` to
@types/bun@1.3.12 / bun-types@1.3.12 (from 1.3.9).
2026-04-23 17:23:39 +08:00
yusing
1f8643a49d docs(api): document inbound_mtls_profile for HTTP routes in swagger
Clarify OpenAPI and the `Route` field: HTTP-based routes only, must
match a configured `inbound_mtls_profiles` entry, and ignored when
`entrypoint.inbound_mtls_profile` is set. Reorder `load_avg_5m` in the
host metrics schema alongside the other load average fields.
2026-04-23 17:23:39 +08:00
yusing
8e21f1320d chore(submodule): update goutils
e744642a65d2cc7c13553f949d994e64ef46111d test(cache): add cold concurrent and in-flight publish regression tests
Cover keyed cache blocking until refreshMu publishes an in-flight entry,
asserting waiters do not trigger duplicate recomputation.

Add stress tests for cold key and cold func paths so concurrent callers
never observe int zero while the value computes exactly once.

24ea5610d1df3f581e92143aff7a6c976b180ed7 feat(cache): add debug-tagged cache observability with summarized logging
Emit zerolog debug events for hits, misses, TTL recompute, usage, and
overflow evictions when built with -tags=debug; non-debug builds compile
in no-op helpers.  Summarize keys and values in logs via formatResult.

Re-check the keyed entry under refreshMu so a just-published cold entry
is not returned as a non-expired hit.  Add tests and README notes.

98c1c1d20a85bd3e36c9609f8c23b1aad30d7dbb chore(deps): bump xsync, zerolog, go-proxyproto, and mongo-driver
Refresh go.sum across the root module plus http/reverseproxy,
http/websocket, and server submodules.

Upgrade xsync to v4.5.0 and zerolog to v1.35.1; bump go-proxyproto to
v0.12.0 in server and mongo-driver v2 to v2.5.1 in http/websocket.

b26d42233f2e295a0d80e9a853d3f9ac2c7fb711 fix(http,server): avoid noisy WebSocket close logs and forced HTTP/3 slog debug
Skip debug error logging in Manager.close for context.Canceled and
net.ErrClosed; log unexpected close errors with Err().

Stop setting slog.LevelDebug on slogzerolog.Option for *http3.Server so the
handler follows the configured zerolog level.

94557c5e86670864de3a95b340ed35f9249ca38c fix(http): align ModifyResponseWriter status with modifier and error paths
Set headerSent and code to 500 when the modifier fails, instead of the
deferred bookkeeping leaving the original WriteHeader argument.

After a successful modifier, write and record resp.StatusCode so the
sent status matches what the modifier set, not only the initial code.

Replace the defer with explicit updates on each branch so state stays
consistent with what is actually written.

7ba8ccefbd9ef415a4371a33150aad15d1179611 feat(http): add HTML 502 page when origin is unreachable
For GET requests that accept HTML, return an embedded page with a retry
countdown and no-store cache headers. Other requests keep the plain text
message.

Ignore **/*.min.* in .gitignore for generated minified HTML assets. Add
tests for HTML and plain text responses.

bdd71fab358c05a17d49fdf39067ecf45304a96f test(events): add History Get bounds, AddAll snapshot races, and benchmarks
Assert Get keeps one global window when mixing categories and that Get
during AddAll never reports a partial batch length.

Benchmark History.Add and SnapshotAndListen under background producers;
use WaitGroup.Go in the cancel stress test; group consts in history.go.
2026-04-23 17:23:39 +08:00
yusing
bf81ad93cc chore(scripts): align refresh-compat placeholders with *.min.* minify layout
Update placeholder generation to use `base.min.ext`, skip files already named
with `.min.` and `internal/go-proxmox`, and discover JS/HTML under
`internal/` and `goutils/` so `go vet` matches the Bun minify script.
2026-04-23 17:23:39 +08:00
yusing
b41528997f chore(deps): refresh Go modules and Docker Bun minify stage
Update go.mod/sum across the root module, agent, internal/dnsproviders, and
socket-proxy (lego, docker/cli, Moby API/client, xsync, zerolog, goutils,
DNS SDKs, genproto RPC). Agent and dnsproviders take godoxy v0.28.0 and newer
replace pseudo-versions.

Switch the Dockerfile minify-stage Bun COPY to oven/bun:1-alpine instead of a
pinned patch tag.
2026-04-23 17:23:39 +08:00
yusing
26fb99734b chore(make): align minify and update-wiki with Bun package layout
Replace minify-js with minify delegating to `bun scripts/minify`. Add
modernize (go fix per module). Drop echo lines from tidy
and dependency update loops. Rename update-wiki entry to index.ts and
invoke it as `bun scripts/update-wiki`.
2026-04-23 17:23:39 +08:00
yusing
dd33980d18 fix(middleware): allow HTML rewrite for chunked and unknown-length bodies
Relax response-body gating so HTML and XHTML can be buffered when
Transfer-Encoding is chunked-only, or when Content-Length is missing,
while still rejecting non-identity encodings that are not chunked HTML
and other non-HTML cases.

Update modifyHTML to cap reads for unknown length, splice the original
stream back when the cap is hit, and document the behavior in the
package README. Extend tests for themed middleware and the rewrite gate.
2026-04-23 17:23:39 +08:00
yusing
167d54ae57 chore(embed): adopt *.min.* for embedded HTML/JS
Point go:embed at block_page.min.html, loading_page.min.html,
loading.min.js, and captcha.min.html.  Update the minified-files
gitignore glob from **/*-min.* to **/*.min.*.
2026-04-23 17:23:39 +08:00
yusing
3cb32dafdd chore(minify): add Bun script to minify internal and goutils HTML/JS
Add `scripts/minify` with glob discovery, @swc/core for JavaScript, and
@swc/html for HTML, writing sibling `*.min.html` / `*.min.js` and
skipping `internal/go-proxmox` and files whose basename already contains
`.min.`. Ship Bun lock, tsconfig, README, and `.gitignore` for the tool.
2026-04-23 17:23:39 +08:00
yusing
05c073e492 refactor(maxmind): replace xsync city cache with goutils and error returns
Remove the xsync map cache and add a 1000-entry goutils keyed cache in
lookup.go. Rrate-limit failure logs, and populate IPInfo.City.

Adjust ACL Geo matchers to the new signature.
2026-04-23 17:23:39 +08:00
yusing
16112054e7 docs(AGENTS): reshape AGENTS.md principles and Go/testing notes
Collapse dev commands into Principles, reference golang-best-practices
for Go style, and consolidate Testing (scoped tests, testify, ldflags).
2026-04-20 16:29:32 +08:00
yusing
7fda4f76e4 chore(swagger): update generated swagger 2026-04-20 16:25:20 +08:00
yusing
586152911f fix(idlewatcher): preserve upstream cache headers when proxying ready targets
Remove the ForceCacheControl wrapper from the ready ServeHTTP path so
proxied responses keep upstream Cache-Control and Expires.

Centralize strong no-store headers via setNoStoreHeaders for the loading
page, static CSS/JS, favicon, and SSE wake events. Add tests covering
loading responses and upstream header preservation.
2026-04-20 16:01:01 +08:00
yusing
2663a703da docs(middleware): update README to clarify request-variable substitution
Added details on request-variable substitution, explaining how it
reads fields from the active outbound request and resolves upstream
variables from the current route context.
v0.28.0
2026-04-19 15:16:54 +08:00
yusing
6ba5833820 fix(example): remove relay_proxy_protocol_header from config example 2026-04-19 15:16:02 +08:00
yusing
c8d7d4f7d3 refactor(acl): memoize IPAllowed with goutils keyed TTL cache
Replace the xsync map plus manual expiry on checkCache with
cache.NewKeyFunc(evaluateIP).WithTTL. Move deny/allow/default logic into
evaluateIP; wire getCachedCity and IPAllowed through the cache API.

Refresh README security notes and add tests showing cached decisions persist
across in-memory rule changes until TTL expires.
2026-04-19 15:15:28 +08:00
yusing
c5b9bd38b7 fix(autocert): synchronize cert renewal and TLS handshake reads
Add per-provider obtain serialization and an RWMutex around shared
provider fields. GetCert and SNI matching use snapshot helpers; rebuild
the matcher atomically; GetExpiries returns a cloned map.

Clone Config.HTTPClient (including Transport) per lego.Config so parallel
providers do not mutate shared client state.

Document the concurrency model in README.
2026-04-19 14:55:14 +08:00
yusing
c219a697f0 chore: update goutils
* test(events): add History Get bounds, AddAll snapshot races, and benchmarks
Assert Get keeps one global window when mixing categories and that Get
during AddAll never reports a partial batch length.

Benchmark History.Add and SnapshotAndListen under background producers;
use WaitGroup.Go in the cancel stress test; group consts in history.go.

* test(synk): refactor pool benchmarks with workerpool
Replace manual work channels and WaitGroup workers with workerpool,
deterministic microsecond jitter, and cpuWork instead of simulateWork.

Adjust concurrent allocation size bands, unsized GetAtLeast, and
ReportAllocs; remove verbose timing metrics. Drop unused newReader in
http body benchmarks.

* fix(io): gate HTTP response flushing on streaming headers
Copy with an http.ResponseWriter destination no longer flushes after
every write unless Content-Type is text/event-stream, or Transfer-Encoding
includes chunked without Content-Length. Buffered responses with
Content-Length skip Flush so fixed-size bodies are not flushed per chunk.

Document the narrowed behavior in README and add tests.

* fix(http): cap modifier buffer preallocation by maxBufferedBytes
When buffering begins, clamp the initial pool buffer size to maxBufferedBytes
when that limit is set. Previously we used max(len(b), Content-Length), which
could reserve a very large slice for a declared body we would never fully
buffer before switching to passthrough.

* fix(http): honor response modifier status in WriteHeader
After a successful modifier run, pass resp.StatusCode to the wrapped writer
instead of the original code so modifiers that change the status code take
effect.

* feat(cache): atomic snapshots, per-refresh backoff, and access-log eviction
Replace mutex-held cached fields with atomic.Pointer snapshots for single-value
and keyed caches so hot reads avoid locking while refreshes stay serialized per
entry.

Build fresh backoff instances per refresh, add context-aware backoff waits, and
skip storing cached values when cancellation matches the returned error.

Keyed caches record access via sequences and logs instead of a global MRU list;
fix janitor pending cleanup when the signal channel is full. Add benchmarks and
tests for cancellation, TTL, and eviction behavior.

* chore(deps): update dependencies
2026-04-19 14:41:51 +08:00
yusing
b122d42a0b fix(test): correct test expectations and logic
Httptest and similar callers often leave Host unset; fall back to URL
for scheme, host, port, and addr substitution.

jsonstore drops the IsTest load short-circuit and duplicate loadNS map
registration; tests isolate storesPath. Skip MaxMind background updates
when IsTest. Tests restore APISkipOriginCheck, use app-scoped OIDC
state cookies, attach route context in middleware helpers, and use
locked buffers for concurrent log capture.
2026-04-19 14:40:22 +08:00
yusing
61f00516dd fix(middleware): stream header-only response rewrites without body buffering
Header-only modifiers no longer use LazyResponseModifier with buffering
always enabled. They wrap the response with ModifyResponseWriter and
return after invoking the next handler.

Body modifiers still use LazyResponseModifier with canBufferAndModifyResponseBody.
Add a regression test that uses a 64MiB Content-Length with a small body.
2026-04-18 14:12:00 +08:00
yusing
64fc885815 chore(make): minify internal JS with bun build, skip go-proxmox
Use `bun build --minify --target browser` instead of `bunx uglify-js` in the
minify-js target.

Exclude `internal/go-proxmox/` from the find pipeline so that tree is not
minified.
2026-04-18 13:35:48 +08:00
yusing
ef21367747 chore(deps): update dependencies 2026-04-18 11:52:47 +08:00
yusing
9068beb0ec chore(example): remove Vary: "*" from example config 2026-04-18 11:18:04 +08:00
Yuzerion
44298d1933 feat: middleware bypass overlay (#221)
* **New Features**
  * Routes can promote route-local bypass rules into matching entrypoint middleware, layering route-specific bypasses onto existing entrypoint rules and avoiding duplicate evaluation.

* **Behavior Changes**
  * Entrypoint middleware updates now refresh per-route overlays at runtime; overlay compilation failures result in HTTP 500 (errors are not exposed verbatim).
  * Route middleware accessors now return safe clones.

* **Documentation**
  * Clarified promotion, consumption, merging and qualification semantics with examples.

* **Tests**
  * Added tests covering promotion, cache invalidation, consumption semantics, and error handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-15 18:35:06 +08:00
Yuzerion
31eea0a885 feat(entrypoint): add inbound mTLS profiles for HTTPS (#220)
Introduce reusable `inbound_mtls_profiles` in root config and support
`entrypoint.inbound_mtls_profile` to require client certificates for all
HTTPS traffic on an entrypoint. Profiles can trust the system CA store,
custom PEM CA files, or both, and are compiled into TLS client-auth
pools during entrypoint initialization.

Also add route-scoped `inbound_mtls_profile` support for HTTP-based
routes when no global entrypoint profile is configured. Route-level mTLS
selection is driven by TLS SNI, preserves existing behavior for open and
unmatched hosts, and returns the intended 421 response when secure
requests omit SNI or when Host and SNI resolve to different routes.

Add validation for missing profile references and unsupported non-HTTP
route usage, update config and route documentation/examples, expand
inbound mTLS handshake and routing regression coverage, and bump
`goutils` for HTTPS listener test support.
2026-04-15 12:14:22 +08:00
Yuzerion
7b00a60f77 fix(docker): merge YAML objects into nested proxy labels (#219)
Sort proxy.* keys by dot depth, then name, before building the tree so
broader paths apply before deeper ones. When a new value would sit on a
node that is already a map, parse it as a YAML object (tabs normalized to
two spaces), deep-merge, and treat an empty string as an empty object.
Return clear errors when a scalar and a nested map disagree.

Drop the preallocated refPrefixes table in favor of refPrefix(n). Add
internal tests for parseLabelObject, mergeLabelMaps, key order, and
flatten; extend export tests for mixed OIDC-style labels and conflicts.

* refactor(docker): extract label parse and flatten helpers

Refactor ParseLabels by moving proxy label application into applyLabel,
descendLabelMap, and setLabelValue so traversal and leaf merge share one path
without labelLoop continues.

Add splitAliasLabel for ExpandWildcard so proxy.* prefix handling stays in one
place and uses CutPrefix/Cut consistently.

Deduplicate flattenMap and flattenMapAny value handling with flattenValue plus
joinLabelKey and stringifyLabelKey for flattened key construction.

* refactor(docker): structured errors for label type clashes

Replace ad hoc fmt.Errorf messages in descendLabelMap, setLabelValue, and
mergeLabelMaps with UnexpectedTypeError so wording is consistent and mapping
vs scalar conflicts stay explicit.

Hoist requireMap in label tests to a shared helper.

Normalize tabs to two spaces in expandYamlWildcard so wildcard YAML matches
the indentation used in the object-merge path.

* refactor(docker): optional UnexpectedTypeError message for merge conflicts

Extend UnexpectedTypeError with an optional Message field; when set, Error()
returns it instead of the default expect-versus-actual formatting.

mergeLabelMaps sets that message when a mapping would merge into an existing
scalar, so the error states the situation instead of only "expect scalar".

Update TestMergeLabelMaps to assert the new wording.
2026-04-13 15:21:42 +08:00
yusing
3de80bf9b1 chore(deps): bump golang.org/x, goutils submodule, and module pins
Refresh indirect and direct golang.org/x pins (crypto, net, sys, text,
arch, mod, tools) across the root module, agent, dnsproviders,
socket-proxy, and h2c_test_server.

Advance the goutils submodule and align pseudo-versions for reverseproxy,
websocket, and server; bump workspace replace commits for agent and
internal/dnsproviders.

Update vultr/govultr to v3.30.0 and mattn/go-isatty to v0.0.21 where they
appear in the graph.
2026-04-13 12:31:46 +08:00
yusing
e0cba8f415 feat(config): opt-in flag for non-loopback local API bind
Validate GODOXY_LOCAL_API_ADDR before starting the unauthenticated local
API. Loopback listeners still succeed by default; addresses that bind
all interfaces, unspecified IPs, LAN hosts, or non-loopback names need
GODOXY_LOCAL_API_ALLOW_NON_LOOPBACK=true.

When that opt-in is set and the host is not loopback, log a warning so
non-local exposure is obvious. Wire common.LocalAPIAllowNonLoopback from
LOCAL_API_ALLOW_NON_LOOPBACK and document it (with a risk note) in
.env.example.

Add TestValidateLocalAPIAddr for loopback, wildcard, LAN, and hostname
cases with the allow flag on and off.
2026-04-13 12:24:52 +08:00
yusing
361189118d chore(make): remove --axios from swagger-typescript-api codegen
Drop the `--axios` flag from the `gen-api-types` target and reflow the
`bunx` `swagger-typescript-api generate` arguments for clearer
continuation lines.

Now generated api.ts is fetch API based and no longer rely on axios.
2026-04-09 16:45:15 +08:00
yusing
5e461842dc fix(serialization): treat empty LoadFileIfExist paths like missing files
When a path exists but reads as empty or whitespace-only, return nil
without touching dst, matching the no-file case. This avoids
unmarshaler errors on blank files and matches the updated doc comment.
2026-04-09 16:44:47 +08:00
yusing
41d0d28ca8 fix(api): confine file edits to rooted config paths and restrict unauthenticated local API binds
Finish the file API traversal fix by rooting both GET and SET operations at the
actual file-type directory instead of the process working directory. This blocks
`..` escapes from `config/` and `config/middlewares/` while preserving valid
in-root reads and writes.

Also harden the optional unauthenticated local API listener so it only starts on
loopback addresses (`localhost`, `127.0.0.1`, `::1`). This preserves same-host
automation while preventing accidental exposure on wildcard, LAN, bridge, or
public interfaces.

Add regression tests for blocked traversal on GET and SET, valid in-root writes,
and loopback-only local API address validation. Fix an unrelated config test
cleanup panic so the touched package verification can run cleanly.

Constraint: `GODOXY_LOCAL_API_ADDR` is documented for local automation and must remain usable without adding a new auth flow

Constraint: File API behavior must keep valid config/provider/middleware edits working while blocking path escapes

Rejected: Mirror the previous GET `OpenInRoot(".", ...)` approach in SET | still allows escapes from `config/` to sibling paths under the working directory

Rejected: Keep unauthenticated non-loopback local API binds and document the risk | preserves a high-severity pre-auth network exposure

Confidence: high

Scope-risk: moderate

Reversibility: clean

Directive: Treat `LOCAL_API_ADDR` as same-host only; if non-loopback unauthenticated access is ever needed, gate it behind a separately named explicit insecure opt-in

Tested: `go test -count=1 -ldflags='-checklinkname=0' ./internal/api/v1/file -run 'Test(Get|Set)_PathTraversalBlocked' -v`

Tested: `go test -count=1 -ldflags='-checklinkname=0' ./internal/config -run '^TestValidateLocalAPIAddr$|^TestRouteValidateInboundMTLSProfile$' -v`

Tested: `go test -count=1 -ldflags='-checklinkname=0' ./internal/api/... ./internal/config/...`

Not-tested: End-to-end runtime verification of fsnotify reload behavior after a valid in-root provider edit
2026-04-09 16:44:01 +08:00
yusing
1c091bbfee chore(deps): bump Go to 1.26.2 and refresh modules
Update Docker builder images and all staged go.mod `go` lines to 1.26.2 for the
root module, agent, cli, bench_server, h2c_test_server, dnsproviders, and
socket-proxy.

Upgrade coreos/go-oidc, docker/cli, valyala/fasthttp, OpenTelemetry HTTP
instrumentation and SDK, Google Cloud auth and API clients, genproto RPC,
OCI DNS SDK, and pinned goutils/http packages; advance the goutils submodule
pointer.
2026-04-08 14:20:52 +08:00
yusing
8e670f15e5 chore(deps): upgrade Go modules and submodule pointers
Bump direct and indirect dependencies across the main module, agent,
dnsproviders package, and socket-proxy: zerolog, lego, validator, Docker CLI,
OpenTelemetry, cloud SDKs, DNS provider clients, and related transitives.

Advance goutils, go-proxmox, and gopsutil submodules; refresh internal
godoxy/agent and dnsproviders pseudo-versions. Extend Moby exclude list for
newer API and client releases to keep older daemon compatibility.
2026-04-04 10:50:20 +08:00
yusing
11e3a9231f fix(route): update path exclusion rules in webui_dev.yml
Add exclusion for all paths under /src/* and modify the websocket protocol header to 'vite-hmr' for improved compatibility with development environments.
v0.27.5
2026-03-21 10:28:48 +08:00
yusing
213e4a5cdb feat(auth): add CSRF protection middleware
Implement Signed Double Submit Cookie pattern to prevent CSRF attacks.
Adds CSRF token generation, validation, and middleware for API endpoints.
Safe methods (GET/HEAD/OPTIONS) automatically receive CSRF cookies, while
unsafe methods require X-CSRF-Token header matching the cookie value with
valid HMAC signature. Includes same-origin exemption for login/callback
endpoints to support browser-based authentication flows.
2026-03-19 14:55:47 +08:00
yusing
a541d75bb5 fix(api/file): prevent path traversal in file API
Use os.OpenRoot to restrict file access to the application root,
preventing directory traversal attacks through the file download endpoint.

Also add test to verify path traversal attempts are blocked.
2026-03-19 10:50:58 +08:00
yusing
f67ef3c519 chore(deps): upgrade dependencies 2026-03-19 10:24:23 +08:00
yusing
3c84692b40 ci: add compat Docker image workflow
Add a new GitHub Actions workflow for building Docker images with the "compat" tag on the compat branch. Also update the existing nightly workflow to only run on the compat branch instead of all branches.
2026-03-11 11:51:07 +08:00