Skip to content

feat(sub): auto-detect subscription format by User-Agent (Updated)#5826

Open
Tomilla wants to merge 9 commits into
MHSanaei:mainfrom
Tomilla:feat_auto_detect_sub_url
Open

feat(sub): auto-detect subscription format by User-Agent (Updated)#5826
Tomilla wants to merge 9 commits into
MHSanaei:mainfrom
Tomilla:feat_auto_detect_sub_url

Conversation

@Tomilla

@Tomilla Tomilla commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds optional User-Agent detection to serve Clash/Mihomo YAML or Xray JSON from the standard subscription URL.

The panel now exposes JSON and Clash/Mihomo endpoint paths, reverse proxy URLs, auto-detection controls, and configurable Go RE2 User-Agent patterns.

Why

Raw, JSON, and Clash subscriptions currently use separate URLs. This is inconvenient for administrators and users migrating from panels that use one subscription URL and select the response format based on the requesting client.

This change retains every existing endpoint while optionally allowing the standard subscription URL to return the appropriate format.

Auto-detection is disabled by default, preserving existing behavior.

Closes #5570

This PR also fixes a bug: when a user has enabled JSON subscription but has no place to modify the JSON subscription path, a prompt "Default JSON subscription path "/json/" is well-known - change it." is constantly displayed upon saving.

Subscription format settings

Type of change

  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Documentation
  • Tests only
  • Build / CI / tooling
  • Other

Areas affected

  • Frontend (UI / panel pages)
  • Backend (API endpoints, login, settings)
  • Xray config generation
  • Subscription (share links / Clash / JSON)
  • Statistics / traffic counters
  • Database / migrations
  • Install / upgrade script
  • Docker image
  • Multi-node (sub-nodes)
  • Telegram bot

How was this tested?

Automated checks:

  • go build ./...
  • go test ./...
  • npm run typecheck
  • npm run lint
  • npm run test -- --run — 704 tests passed
  • npm run build

Manual subscription checks:

  • Recognized Clash/Mihomo User-Agents receive Clash YAML from the standard subscription URL.
  • Recognized Xray JSON User-Agents receive a JSON configuration array.
  • v2rayNG and unknown clients continue receiving the existing raw/Base64 subscription.
  • Requests accepting HTML continue displaying the subscription information page.
  • Disabling auto-detection preserves the existing response.
  • Explicit raw, JSON, and Clash/Mihomo URLs remain available.
  • Custom patterns are validated using Go RE2 before saving.
  • Empty patterns remain empty in the database and inherit runtime defaults.
  • Explicit JSON single-profile responses retain legacy object behavior unless “Always return a JSON array” is enabled.

Screenshots / recordings

Subscription settings link

Subscription settings link

JSON and Clash/Mihomo format settings

JSON and Clash/Mihomo format settings

User-Agent auto-detection

User-Agent auto-detection settings

Go RE2 validation

User-Agent regex:

Invalid User-Agent regex error

Breaking changes

None.

Existing subscription URLs and response behavior remain unchanged unless an administrator explicitly enables auto-detection. Existing JSON and Clash/Mihomo endpoints remain available.

Checklist

  • I tested the change locally and confirmed the described behavior.
  • I added or updated tests for the new behavior (when applicable).
  • go build ./... and the test suite pass locally.
  • For frontend changes: npm run lint, npm run typecheck, and npm run build pass.
  • I updated the Wiki / README / API docs if user-facing behavior changed.
  • My commits follow the project's existing message style.
  • I have no unrelated changes mixed into this PR.

@github-actions github-actions Bot added go Pull requests that update Go code javascript Pull requests that update javascript code New Feature bug Something isn't working labels Jul 6, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment - verifying tooling access, will follow up with full review shortly.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff and traced the new auto-detect path end to end (internal/sub/controller.go, internal/sub/sub.go, internal/web/service/setting.go, internal/web/controller/setting.go), and cross-checked the generated OpenAPI/frontend artifacts plus all 13 translation files.

This is a well-engineered, backward-compatible change: auto-detection defaults to off and is gated behind both the auto-detect flag and the underlying format being enabled, the NewSUBController functional-options refactor threads every option through correctly at its only call site (internal/sub/sub.go), the new User-Agent regexes are validated both client-side (GoRegexInput) and server-side (validateSubUserAgentRegexes in internal/web/service/setting.go) with a sensible empty-inherits-default contract, and all 13 locale JSON files received the new keys (verified they parse and contain the expected key set). No correctness, security, or backward-compatibility problems were found.

Two non-blocking suggestions, both inline below:

  • A cosmetic indentation regression in endpoints.ts on the two pre-existing entries this PR edited.

  • The Balancer cost-regex validation UX in BalancerFormModal.tsx is unrelated to subscription format auto-detection; consider splitting it into its own PR.

This review was generated automatically by an AI agent; a maintainer may still want to follow up. An earlier placeholder comment posted on this PR during tooling verification can be disregarded.

Comment thread frontend/src/pages/api-docs/endpoints.ts Outdated
Comment thread frontend/src/pages/api-docs/endpoints.ts Outdated
Comment thread frontend/src/pages/xray/balancers/BalancerFormModal.tsx Outdated
@Tomilla

Tomilla commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

The CI failure was caused by the following network error, and it is not a problem with the PR code.

go: downloading github.com/wlynxg/anet v0.0.5
Error: ../../../go/pkg/mod/github.com/xtls/xray-core@v1.260327.1-0.20260627131803-45cf2898ab12/transport/internet/hysteria/congestion/bbr/windowed_filter.go:4:2: golang.org/x/exp@v0.0.0-20260611194520-c48552f49976: read "https://proxy.golang.org/golang.org/x/exp/@v/v0.0.0-20260611194520-c48552f49976.zip": stream error: stream ID 309; INTERNAL_ERROR; received from peer
Error: Process completed with exit code 1.

Tomilla and others added 2 commits July 6, 2026 16:17
…ntRegex

- Use NewErrorf with proper formatting instead of NewError with string concatenation
- Add comment explaining the rationale for returning original pattern value
- This preserves the intentional design where empty input is stored as empty
  in the DB and inherited as the runtime default at read time
@Tomilla

Tomilla commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

All suggestions have been addressed. The PR is ready for review.

MHSanaei added 2 commits July 8, 2026 21:14
… apps

Repo policy forbids third-party client app names in source and locale strings. Removes Streisand/Stash/v2rayN(G/A) from Go defaults, TSX placeholders, entity descriptions, and all 13 locales; keeps allowed format names Clash/Mihomo. Trims added Go comments. Merges current main and regenerates OpenAPI/schemas.
@Tomilla

Tomilla commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

0944dd4
refactor(sub): describe UA auto-detect behavior without naming client apps

Repo policy forbids third-party client app names in source and locale strings. Removes Streisand/Stash/v2rayN(G/A) from Go defaults, TSX placeholders, entity descriptions, and all 13 locales; keeps allowed format names Clash/Mihomo. Trims added Go comments. Merges current main and regenerates OpenAPI/schemas.

I fully agree with this approach in the interest of maintaining platform neutrality.

When configurable regular expressions were originally added, the intent was precisely to give users the flexibility to make adjustments based on their actual User-Agents. Since some clients (like V2rayA and V2rayNG) cannot adjust their User-Agents autonomously, while others (like Clash Verge and Premium) support custom User-Agents, relying on user-configured regex rather than hardcoded client names makes perfect sense.

@MHSanaei I fully support these adjustments. Are there any other review comments or further changes needed before we move forward?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working go Pull requests that update Go code javascript Pull requests that update javascript code New Feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Clash and XRay subscriptions on one URL

2 participants