Two related gaps on the Hysteria side of the subscription layer:
1) `genHysteriaLink` ignored `externalProxy` entirely, so an admin who
pointed a Hysteria inbound at an alternate endpoint (e.g. a CDN
hostname forwarding UDP back to the node) still got a link with the
original server address. Mirror what `genVlessLink` / `genTrojanLink`
already do: fan out one link per entry, substituting `dest` / `port`
and picking up the entry's remark suffix. As a bonus, the salamander
obfs password is now copied into the URL too — the panel-side link
generator already did this, so the subscription output was lagging
behind it.
2) `buildProxy` in `subClashService.go` had a protocol switch with cases
for VMESS / VLESS / Trojan / Shadowsocks and a `default: return nil`.
Hysteria inbounds fell into the default branch and silently vanished
from the Clash YAML. Route Hysteria to a dedicated
`buildHysteriaProxy` helper before the transport/security helpers run
(applyTransport / applySecurity model xray streams, which Hysteria
doesn't use).
`buildHysteriaProxy` reads `inbound.StreamSettings` directly instead
of going through `streamData` / `tlsData`, because those prune
fields (`allowInsecure`, the salamander `finalmask.udp` block) that
the mihomo Hysteria proxy wants preserved. Output shape matches
mihomo's expectations:
type: hysteria2 # or "hysteria" for v1
password / auth-str: <client auth>
sni, alpn, skip-cert-verify, client-fingerprint
obfs: salamander
obfs-password: <finalmask.udp[salamander].settings.password>
The existing `getProxies` fanout over `externalProxy` already plugs in
for Clash, so with Hysteria now recognised, External Proxy entries
also flow through to the Clash output for Hysteria inbounds.
Closes#4053
* docs(agents): add AI agent guidance documentation
* feat(sub): add Clash/Mihomo YAML subscription service
Add SubClashService to convert subscription links to Clash/Mihomo
YAML format for direct client compatibility.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sub): integrate Clash YAML endpoint into subscription system
- Add Clash route handler in SUBController
- Update BuildURLs to include Clash URL
- Pass Clash settings through subscription pipeline
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web): add Clash settings to entity and service
- Add SubClashEnable, SubClashPath, SubClashURI fields
- Add getter methods for Clash configuration
- Set default Clash path to /clash/ and enable by default
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ui): add Clash settings to subscription panels
- Add Clash enable switch in general subscription settings
- Add Clash path/URI configuration in formats panel
- Display Clash QR code on subscription page
- Rename JSON tab to "Formats" for clarity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(js): add Clash support to frontend models
- Add subClashEnable, subClashPath, subClashURI to AllSetting
- Generate and display Clash QR code on subscription page
- Handle Clash URL in subscription data binding
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
Unsafe type assertion `xhttp["mode"].(string)` panics when mode is
nil (e.g., when xhttpSettings only contains path without mode). The
panic is caught by Gin's recovery middleware and returned as HTTP 500.
Use comma-ok pattern matching the fix already applied to gRPC's
authority field in 21d98813.
Fixes#3987
* vless: use Inbound Listen address in Subscription service
vless manual connection link and subscription produced connection link are aligned.
subscription service now returns an IP address configured on Inbound, instead of subscription service IP,
which is consistent when the address, returned by QR code for manual vless link distribution.
* [refactor] api controller
* [fix] access log path
better to not hardcode the access log path, maybe some ppl dont want to use the default ./access.log
* [fix] set select options from logs paths in xray settings
* [update] .gitignore
* [lint] all .go files
* [update] use status code for jsonMsg and 401 to unauthorize
* [update] handle response status code via axios
* [fix] set correct value if log paths is set to 'none'
we also use the default value for the paths if its set to none
* [fix] iplimit - only warning access log if f2b is installed