fix(api): support apikey query param with custom base URL - #748
Conversation
The auth middleware used exact path matching for the /cross-seed/apply endpoint, which failed when a custom base URL was configured (e.g., /qui/api/cross-seed/apply instead of /api/cross-seed/apply). Changed to use HasSuffix/Contains for path matching to work with any base URL configuration.
WalkthroughThe authentication middleware's path-matching logic for API key query parameter extraction was broadened to support custom base URLs, changing from exact path prefixes to pattern matching using contains/hasSuffix operations. A corresponding test was added to validate authentication across multiple custom base URL scenarios. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10–15 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
internal/api/middleware/auth.go (1)
26-28: Path matching change looks correct and scoped; consider future-proofing via shared constantsThe new
strings.Contains(path, "/cross-seed/webhook/") || strings.HasSuffix(path, "/cross-seed/apply")check correctly fixes the custom base URL issue while still limiting query-based API key extraction to the intended cross‑seed endpoints. The header‑first lookup also preserves existing behavior for clients that useX-API-Key.If you anticipate more cross‑seed endpoints or reuse of these paths elsewhere, consider pulling
"/cross-seed/webhook/"and"/cross-seed/apply"into shared constants to avoid drift between middleware and tests, but that’s optional given current scope.internal/api/middleware/auth_test.go (1)
108-124: Optionally build URLs viaurl.Valuesfor robustness against future key formatsRight now the URL for test requests is constructed via string concatenation:
url := tt.path if tt.apiKeyQuery != "" { url += "?apikey=" + tt.apiKeyQuery }If API keys ever include characters that need URL‑encoding, this could become brittle. Consider using
url.Values(orreq.URL.Query()+Encode()) to set theapikeyparameter instead. It keeps the test resilient to format changes with minimal extra code.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
internal/api/middleware/auth.go(1 hunks)internal/api/middleware/auth_test.go(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
internal/api/middleware/auth_test.go (1)
internal/api/middleware/auth.go (1)
IsAuthenticated(19-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Run tests
🔇 Additional comments (1)
internal/api/middleware/auth_test.go (1)
20-106: Good, focused coverage of custom base URL and API key behaviorsThe test setup and table cases do a solid job of pinning down the intended semantics:
- Valid keys via
apikeyquery param across default and multiple custom base URLs.- Valid key via
X-API-Keyheader.- Differentiation between 401 (invalid key) and 403 (no auth / non‑whitelisted endpoint).
- Guard that non‑webhook endpoints do not start accepting
apikeyquery params by accident.This gives strong regression protection around the new path-matching logic.
This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/autobrr/qui](https://github.com/autobrr/qui) | minor | `v1.9.1` -> `v1.10.0` | --- ### Release Notes <details> <summary>autobrr/qui (ghcr.io/autobrr/qui)</summary> ### [`v1.10.0`](https://github.com/autobrr/qui/releases/tag/v1.10.0) [Compare Source](autobrr/qui@v1.9.1...v1.10.0) #### Changelog ##### New Features - [`f2b17e6`](autobrr/qui@f2b17e6): feat(config): add SESSION\_SECRET\_FILE env var ([#​661](autobrr/qui#661)) ([@​undefined-landmark](https://github.com/undefined-landmark)) - [`f5ede56`](autobrr/qui@f5ede56): feat(crossseed): add RSS source filters for categories and tags ([#​757](autobrr/qui#757)) ([@​s0up4200](https://github.com/s0up4200)) - [`9dee7bb`](autobrr/qui@9dee7bb): feat(crossseed): add Unicode normalization for title and file matching ([#​742](autobrr/qui#742)) ([@​s0up4200](https://github.com/s0up4200)) - [`d44058f`](autobrr/qui@d44058f): feat(crossseed): add skip auto-resume settings per mode ([#​755](autobrr/qui#755)) ([@​s0up4200](https://github.com/s0up4200)) - [`9e3534a`](autobrr/qui@9e3534a): feat(crossseed): add webhook source filters for categories and tags ([#​763](autobrr/qui#763)) ([@​s0up4200](https://github.com/s0up4200)) - [`c8bbe07`](autobrr/qui@c8bbe07): feat(crossseed): only poll status endpoints when features are enabled ([#​738](autobrr/qui#738)) ([@​s0up4200](https://github.com/s0up4200)) - [`fda8101`](autobrr/qui@fda8101): feat(sidebar): add size tooltips and deduplicate cross-seed sizes ([#​724](autobrr/qui#724)) ([@​s0up4200](https://github.com/s0up4200)) - [`e4c0556`](autobrr/qui@e4c0556): feat(torrent): add sequential download toggles ([#​776](autobrr/qui#776)) ([@​rare-magma](https://github.com/rare-magma)) - [`2a43f15`](autobrr/qui@2a43f15): feat(torrents): autocomplete paths ([#​634](autobrr/qui#634)) ([@​rare-magma](https://github.com/rare-magma)) - [`1c07b33`](autobrr/qui@1c07b33): feat(torrents): replace filtered speeds with global ([#​745](autobrr/qui#745)) ([@​jabloink](https://github.com/jabloink)) - [`cd0deee`](autobrr/qui@cd0deee): feat(tracker): add per-domain stats inclusion toggle for merged trackers ([#​781](autobrr/qui#781)) ([@​s0up4200](https://github.com/s0up4200)) - [`b6a6200`](autobrr/qui@b6a6200): feat(web): add Size column to Tracker Breakdown table ([#​770](autobrr/qui#770)) ([@​s0up4200](https://github.com/s0up4200)) - [`560071b`](autobrr/qui@560071b): feat(web): add zebra striping to torrent table ([#​726](autobrr/qui#726)) ([@​s0up4200](https://github.com/s0up4200)) - [`f8f65a8`](autobrr/qui@f8f65a8): feat(web): improve auto-search on completion UX ([#​743](autobrr/qui#743)) ([@​s0up4200](https://github.com/s0up4200)) - [`e36312f`](autobrr/qui@e36312f): feat(web): improve torrent selection UX with unified click and escape behavior ([#​782](autobrr/qui#782)) ([@​s0up4200](https://github.com/s0up4200)) - [`27c1daa`](autobrr/qui@27c1daa): feat(web): napster theme ([#​728](autobrr/qui#728)) ([@​s0up4200](https://github.com/s0up4200)) - [`e3950de`](autobrr/qui@e3950de): feat(web): new torrent details panel for desktop ([#​760](autobrr/qui#760)) ([@​s0up4200](https://github.com/s0up4200)) - [`6c66ba5`](autobrr/qui@6c66ba5): feat(web): persist tab state in URL for CrossSeed and Settings pages ([#​775](autobrr/qui#775)) ([@​s0up4200](https://github.com/s0up4200)) - [`59884a9`](autobrr/qui@59884a9): feat(web): share tracker customizations with filtersidebar ([#​717](autobrr/qui#717)) ([@​s0up4200](https://github.com/s0up4200)) ##### Bug Fixes - [`fafd278`](autobrr/qui@fafd278): fix(api): add webhook source filter fields to PATCH settings endpoint ([#​774](autobrr/qui#774)) ([@​s0up4200](https://github.com/s0up4200)) - [`bdf0339`](autobrr/qui@bdf0339): fix(api): support apikey query param with custom base URL ([#​748](autobrr/qui#748)) ([@​s0up4200](https://github.com/s0up4200)) - [`c3c8d66`](autobrr/qui@c3c8d66): fix(crossseed): compare Site and Sum fields for anime releases ([#​769](autobrr/qui#769)) ([@​s0up4200](https://github.com/s0up4200)) - [`cb4c965`](autobrr/qui@cb4c965): fix(crossseed): detect file name differences and fix hasExtraSourceFiles ([#​741](autobrr/qui#741)) ([@​s0up4200](https://github.com/s0up4200)) - [`fd9e054`](autobrr/qui@fd9e054): fix(crossseed): fix batch completion searches and remove legacy settings ([#​744](autobrr/qui#744)) ([@​s0up4200](https://github.com/s0up4200)) - [`26706a0`](autobrr/qui@26706a0): fix(crossseed): normalize punctuation in title matching ([#​718](autobrr/qui#718)) ([@​s0up4200](https://github.com/s0up4200)) - [`db30566`](autobrr/qui@db30566): fix(crossseed): rename files before folder to avoid path conflicts ([#​752](autobrr/qui#752)) ([@​s0up4200](https://github.com/s0up4200)) - [`8886ac4`](autobrr/qui@8886ac4): fix(crossseed): resolve category creation race condition and relax autoTMM ([#​767](autobrr/qui#767)) ([@​s0up4200](https://github.com/s0up4200)) - [`f8f2a05`](autobrr/qui@f8f2a05): fix(crossseed): support game scene releases with RAR files ([#​768](autobrr/qui#768)) ([@​s0up4200](https://github.com/s0up4200)) - [`918adee`](autobrr/qui@918adee): fix(crossseed): treat x264/H.264/H264/AVC as equivalent codecs ([#​766](autobrr/qui#766)) ([@​s0up4200](https://github.com/s0up4200)) - [`c4b1f0a`](autobrr/qui@c4b1f0a): fix(dashboard): merge tracker customizations with duplicate displayName ([#​751](autobrr/qui#751)) ([@​jabloink](https://github.com/jabloink)) - [`3c6e0f9`](autobrr/qui@3c6e0f9): fix(license): remove redundant validation call after activation ([#​749](autobrr/qui#749)) ([@​s0up4200](https://github.com/s0up4200)) - [`a9c7754`](autobrr/qui@a9c7754): fix(reannounce): simplify tracker detection to match qbrr logic ([#​746](autobrr/qui#746)) ([@​s0up4200](https://github.com/s0up4200)) - [`3baa007`](autobrr/qui@3baa007): fix(rss): skip download when torrent already exists by infohash ([#​715](autobrr/qui#715)) ([@​s0up4200](https://github.com/s0up4200)) - [`55d0ccc`](autobrr/qui@55d0ccc): fix(swagger): respect base URL for API docs routes ([#​758](autobrr/qui#758)) ([@​s0up4200](https://github.com/s0up4200)) - [`47695fd`](autobrr/qui@47695fd): fix(web): add height constraint to filter sidebar wrapper for proper scrolling ([#​778](autobrr/qui#778)) ([@​s0up4200](https://github.com/s0up4200)) - [`4b3bfea`](autobrr/qui@4b3bfea): fix(web): default torrent format to v1 in creator dialog ([#​723](autobrr/qui#723)) ([@​s0up4200](https://github.com/s0up4200)) - [`2d54b79`](autobrr/qui@2d54b79): fix(web): pin submit button in Services sheet footer ([#​756](autobrr/qui#756)) ([@​s0up4200](https://github.com/s0up4200)) - [`2bcd6a3`](autobrr/qui@2bcd6a3): fix(web): preserve folder collapse state during file tree sync ([#​740](autobrr/qui#740)) ([@​ewenjo](https://github.com/ewenjo)) - [`57f3f1d`](autobrr/qui@57f3f1d): fix(web): sort Peers column by total peers instead of connected ([#​759](autobrr/qui#759)) ([@​s0up4200](https://github.com/s0up4200)) - [`53a8818`](autobrr/qui@53a8818): fix(web): sort Seeds column by total seeds instead of connected ([#​747](autobrr/qui#747)) ([@​s0up4200](https://github.com/s0up4200)) - [`d171915`](autobrr/qui@d171915): fix(web): sort folders before files in torrent file tree ([#​764](autobrr/qui#764)) ([@​s0up4200](https://github.com/s0up4200)) ##### Other Changes - [`172b4aa`](autobrr/qui@172b4aa): chore(assets): replace napster.svg with napster.png for logo update ([@​s0up4200](https://github.com/s0up4200)) - [`dc83102`](autobrr/qui@dc83102): chore(deps): bump the github group with 3 updates ([#​761](autobrr/qui#761)) ([@​dependabot](https://github.com/dependabot)\[bot]) - [`75357d3`](autobrr/qui@75357d3): chore: fix napster logo ([@​s0up4200](https://github.com/s0up4200)) - [`206c4b2`](autobrr/qui@206c4b2): refactor(web): extract CrossSeed completion to accordion component ([#​762](autobrr/qui#762)) ([@​s0up4200](https://github.com/s0up4200)) **Full Changelog**: <autobrr/qui@v1.9.1...v1.10.0> #### Docker images - `docker pull ghcr.io/autobrr/qui:v1.10.0` - `docker pull ghcr.io/autobrr/qui:latest` #### What to do next? - Join our [Discord server](https://discord.autobrr.com/qui) Thank you for using qui! </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi4zOS4xIiwidXBkYXRlZEluVmVyIjoiNDIuMzkuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW1hZ2UiXX0=--> Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/2664 Co-authored-by: Renovate Bot <renovate-bot@alexlebens.net> Co-committed-by: Renovate Bot <renovate-bot@alexlebens.net>
The auth middleware used exact path matching for the /cross-seed/apply endpoint, which failed when a custom base URL was configured (e.g., /qui/api/cross-seed/apply instead of /api/cross-seed/apply).
Changed to use HasSuffix/Contains for path matching to work with any base URL configuration.
Summary by CodeRabbit
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.