main
93
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a46b3b010b |
feat(listener): HTTP/SOCKS inbounds with client share and Clash proxies
Re-apply on post-theme baseline (
|
||
|
|
f18419da8b |
fix(listener): allow TCP and UDP listeners to share a port (#91)
The endpoint conflict guard in ensureEndpointAvailable (and its batch counterpart ensureBatchEndpointsAvailable) compared only port ranges and bind addresses — it never looked at the L4 protocol. A TCP listener on 443 and a UDP listener on 443 are independent sockets at the OS level and Mihomo serves both fine, but 3m-ui rejected the second one with "conflicts on 0.0.0.0:443". So you could not run e.g. VLESS (TCP) and TUIC/Hysteria2 (UDP) on the same port. Add protocol.ListenerTransports, which maps a listener's protocol kind to the L4 transport(s) its inbound binds (UDP for tuic / hysteria / hysteria2 / shadowquic / mieru; TCP for everything else). The proxy `udp` toggle is UDP relay over an established connection and is intentionally ignored — it does not open a UDP listening socket. The conflict check now also requires the two listeners to share an L4 transport, so a TCP+UDP pair on the same address:port no longer collides while two TCP or two UDP listeners still do. Tests: - protocol.ListenerTransports unit tests (udp/tcp/case-insensitive). - listener.listenersShareTransport unit tests. - End-to-end: a TCP+UDP pair on 443 coexists and the UDP listener stays on 443 through Create (it is not silently reassigned to a free port), while two TCP or two UDP on 443 still conflict. Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> |
||
|
|
615b199888 | fix(ci): set Listener ID via embedded BaseModel in export/share | ||
|
|
aac7517172 | fix(protocol): add NodeModel.ID for certstore-backed share TLS | ||
|
|
842fd72ea4 |
refactor(export): unify TLS profile for URI, share and subscription
Introduce internal/export as the single cert/SNI/skip-cert resolver. ClientURIs, DecodeNodeModel, resolveShareTLS and Clash proxy TLS helpers all consume BuildProfileFromConfig so formal IP certs always emit sni and subscriptions no longer diverge from share links on certificate identity. |
||
|
|
05816736a0 |
fix(share,uri): load certstore PEM and always emit HY2 sni
DecodeNodeModel now sets listener ID and materializes certificate paths or certstore PEM. resolveShareTLS expands paths and never leaves SNI empty on IP hosts. HY2 share/URI default alpn=h3 and force sni=host when unresolved so Loon no longer sees bare host:port links. |
||
|
|
b36f930099 | fix(sub,share,uri): unify SNI/skip-cert across all protocol exports | ||
|
|
91a9f924a4 | fix(share): emit HY2 SNI for IP hosts (formal cert path) | ||
|
|
32c6aee335 |
fix(sub): stop forcing skip-cert-verify for formal certificates
Rewrite DecideClientSkipCertVerify: CA-signed / non-self-signed PEMs never force insecure; domain endpoints without embedded PEM rely on system CAs; IP-only without PEM still skips. URI export loads certstore PEM, prefers SNI as verify identity, and HY2/VLESS share paths use the same decision. |
||
|
|
bbe10da416 |
fix(release,hy2): sane auto release notes; Loon-friendly HY2 share links
Release workflow: previous stable tag only, merge-base range, first-parent log, noise filter, and per-section caps so notes stay readable. Hysteria2 share/URI: resolve SNI from access profile/public host, emit allowInsecure alongside insecure, encode userinfo via url.User so Loon and similar clients can complete TLS. |
||
|
|
96dc3b38a2 | style: align VMess test fields | ||
|
|
e75a5847d7 | style: format VMess changes | ||
|
|
fcd5fb8dee | test: preserve VMess per-user alterId | ||
|
|
caff433bcc | fix: preserve VMess per-user alterId on compile | ||
|
|
8507b8636c |
fix(sub): audit URI and YAML export for CDN access fields
Fill security=tls, sni, fp, and ws host from AccessSNI/PublicHost for domain+WS share links and client YAML; default fingerprint chrome. |
||
|
|
d2a80f5f80 |
fix(protocol): strip ws-headers from VLESS/VMess listeners
Mihomo inbound only supports ws-path for WebSocket; headers are client-side. Keep ws-headers in panel config for share/export. |
||
|
|
fec9733baa |
docs: remove third-party panel name references from copy
Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. docs: remove third-party panel name references from copy Drop and external m-ui product names from docs, UI strings, and code comments. Keep functional descriptions of server egress and WARP. |
||
|
|
af01f1f237 | fix(share): emit VLESS WS host in URI when ws-headers empty | ||
|
|
f9f5c66fed |
fix(ci,sub): gofmt + align sing-box TUN with official schema
Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. fix(ci,sub): gofmt + align sing-box TUN with official schema Use official Tun address example (172.18.0.1/30 + ULA IPv6) and keep auto_route/strict_route/stack per sing-box docs. |
||
|
|
b664e57117 |
fix(share): CDN VLESS/WS export Host + path defaults
When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. fix(share): CDN VLESS/WS export Host + path defaults When ws-headers Host is empty, client URI/YAML/subscription now fall back to SNI or public host. Always emit WS path (default /). Panel gains an explicit WebSocket Host field for CDN setups. |
||
|
|
35f4c521c3 |
fix(vless): stop exporting flow on transports that cannot carry it (#87)
* fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> fix(vless): stop exporting flow on transports that cannot carry it (#87) * fix(vless): stop exporting flow on transports that cannot carry it The form promised that flow is cleared for ws/grpc/xhttp and the tooltip still says so, but exported links kept carrying flow=xtls-rprx-vision. Two separate reasons, both fixed. The clear came too late to matter. formValuesToConfig wrote `flow` into the config inside the protocol switch, and only afterwards did the "Vision is TCP-only" rule run — where it mutated the form state, not the config it had already been copied into. The transport is now resolved before anything writes, and the drop also removes a flow inherited from the previous config, so changing a listener's transport actually takes effect. The URI generators never asked. Every one of them emitted whatever flow it found: - node: vlessURIs decided flow before resolving the transport, so the type it had just computed was irrelevant to the decision. It now resolves the transport first. ClientURIsWithCredentials also merged the listener-level flow onto every user on protocol alone, which reintroduced the value the form had dropped. - protocol: the share URI and the client YAML both wrote spec.Flow unguarded, even though TransportSpec knows the network. Same for the server-side compile, which pushed the listener default onto users — Mihomo rejects that combination outright, so this one takes the listener down. - mui: BuildVLESSShare set flow unconditionally, and bridge.go injected the listener default into users before it was known to be applicable. - converter: copyTransport resolved `network` but left a stale flow behind. The rule is now one predicate per representation: TransportSpec.CarriesFlow, VLESSHandlerSpec.CarriesFlow, and protocol.TransportCarriesFlow for raw configs. TCP/raw keeps Vision; ws, grpc, xhttp, mkcp and mekya never emit it. Tests pin each path in both directions — a stale flow disappears on ws/grpc/ xhttp, and a genuine TCP listener keeps its flow. The frontend one runs the real form builder and fails, in three of five cases, against the previous ordering. * fix(uri): carry vmess ws Host and align hysteria2 TLS flags across user shapes Auditing the remaining exporters after the flow fix turned up two more places where the link disagreed with the listener. vmessURIs built its JSON by hand instead of going through transportParams, so a ws listener that pins a Host header exported only the path: the client had nothing to send as Host and the listener was unreachable through the link, even though the client YAML built from the same config worked. It also dropped allowInsecure, which vless and trojan both carry — a listener whose certificate the client cannot verify exported a link that failed the handshake. The repeated tlsParams() calls were hoisted while touching this. hysteria2URIs reads users either as rows or as a map, and the two branches disagreed: one asked certutil.ShouldSkipCertVerify and emitted only `insecure`, the other asked clientSkipCert and emitted `insecure` plus `allowInsecure`. The same listener therefore produced different links depending on how its users were stored. Both now use clientSkipCert, the helper intended for share URIs, and emit both keys. Not fixed, for the record: an SS listener with simple-obfs exports a bare ss:// link with no `plugin=` entry, so the obfs configuration is lost. The client YAML does translate it (plugin: obfs). Fixing the URI means committing to a SIP002 plugin encoding that varies between clients, which is worth deciding separately rather than guessing at here. * i18n: complete zh-CN and guard against the locale regressions already seen zh-CN was missing seven listener hints that en.ts declares, so those tooltips rendered in English for the primary UI language. Translated: client_auth_cert, client_auth_type, ech_key, enable_pure_downlink, mux, padding and table_type. The rest of the catalogue is deliberately left alone. Seventeen locales each lack 65 keys that en.ts has; the provider already resolves those from en.ts, so they degrade to English rather than breaking, and filling 1100 strings with unreviewed machine translation would be worse than the fallback. The test prints the per-locale gap so it stays visible. The new locale test guards the regressions this directory has actually hit: a duplicated key inside one object (which breaks the type check), and a key renamed in en.ts leaving an orphan behind. It also asserts zh-CN stays complete, since a gap there reads as a defect rather than as translation lag. * i18n: declare the 24 keys the UI asks for but no locale ever defined Twenty-four keys were referenced from components without being declared in any locale, so t() fell through to its hardcoded fallback. Where a fallback existed that merely meant the string could never be translated; where none existed — protocolHint, access_sniHint, jlsHint, shadowTlsHint and the rest — the tooltip either rendered the raw key, "listeners.protocolHint", or disappeared entirely, because fieldTip() suppresses a value that equals the key it looked up. en.ts takes the text the code was already falling back to, so nothing changes on screen; the strings just become translatable. The few without a fallback were written from the surrounding context — the field they annotate, its placeholder, and the wording of the neighbouring hints. trafficMultiplierHint is the exception: its fallback was Chinese, which is wrong for the English catalogue, so it now has a real English string. zh-CN gets all twenty-four, which keeps it complete against en.ts. The locale test now reads through the TypeScript AST. It previously parsed line by line and these files contain minified regions — several "key":"value" pairs on one line — so a whole block of keys was invisible to it, which is how this gap stayed hidden. It also gained the assertion that would have caught the bug directly: every dotted key handed to t() or fieldTip() must be declared in en.ts. The remaining languages still lag, now by 89 keys rather than 65, and still fall back to English; the test prints the per-locale figure. * fix(uri): drop the vmess allowInsecure field the reference client ignores The vmess skip-certificate field was added on internal consistency alone — vless and trojan carry allowInsecure in their query strings, so vmess looked like an oversight. Checked against the client that actually parses these links, it is not one. v2rayN's VmessQRCode model declares exactly: v, ps, add, port, id, aid, scy, net, type, host, path, tls, sni, alpn, fp. There is no skip-certificate field at all — neither allowInsecure nor insecure — so the field was dead weight in a payload that v2rayN reads field by field. v2rayNG reads `insecure` instead, and Xray-core has removed allowInsecure in favour of pinnedPeerCertSha256, so there is no spelling that the reference clients agree on. Emitting one would have produced a link that looks configured but is not. The ws `host` fix stands: v2rayN's own documentation lists "ws host" as the meaning of that field, so dropping it broke ws listeners that pin a Host. The conformance test now pins the emitted payload to v2rayN's field set, so a future field copied over from another protocol fails instead of being silently ignored by every client. Deliberately left alone, both confirmed against the official scheme and worth deciding separately: - hysteria2 links carry up/down. The Hysteria 2 URI specification is explicit that the parameters "should never include client modes ... or bandwidth values". Removing them changes behaviour for anyone relying on the link, so it is flagged rather than removed. `insecure` is the official parameter; allowInsecure is kept alongside it purely for clients that read that name. - an SS listener with simple-obfs still exports a bare ss:// link with no plugin entry, losing the obfuscation the client YAML does translate. Also noted while checking: tuicURIs defaults congestion_control to bbr where sing-box documents cubic as its default. Ours is set explicitly, which is valid, but the comment claiming it is what "most TUIC clients" use is not sourced. * fix(uri): keep vmess allowInsecure after all Reverts the revert. Dropping it was correct on the evidence and wrong on the consequences: v2rayN ignores the field, v2rayNG spells it `insecure`, and Xray-core has moved to pinnedPeerCertSha256 — but the clients that do read allowInsecure are precisely the ones whose handshake fails without it, and an ignored extra key costs the others nothing. Removing it would have traded a working link for a tidy payload. The conformance test keeps its guard, with allowInsecure recorded as an explicit, justified exception rather than a silent inclusion: the field set is still pinned to v2rayN's model, so any further field copied over from another protocol has to argue its way in. * fix(uri): restore the vmess ws Host in registry YAML, and stop dropping share links Two leftovers from auditing the exporters end to end. The registry's VMess compiler built ws-opts with the path only, so a listener that pins a Host exported a client config with nothing to send as Host. The vless YAML path in the same file already nests it under `headers` per the mihomo wiki, so this just mirrors that — and the converter has always carried it, which is how the difference went unnoticed. The node URI share endpoint also had a tier that could not be reached. It walks three tiers — m-ui, the registry, then the legacy builders — and the second one gates the third on having neither a URI nor client YAML. But the registry implements URI export for a different protocol set than the legacy builders: it compiles vmess, snell, shadowquic, mieru, sudoku and trusttunnel to client YAML without ever emitting a URI, so those listeners arrived at the third tier with a YAML in hand and the condition already false, and reported no link at all even though ClientURIsWithCredentials exports one. The third tier now runs whenever the URI is still missing, and only fills in YAML that earlier tiers did not already provide. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> |
||
|
|
4b21501deb |
feat(ui): in-panel field help tooltips + i18n (wiki-aligned)
Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. feat(ui): in-panel field help tooltips + i18n (wiki-aligned) Expand protocol capability descriptions from Mihomo Meta concepts, auto-attach Form.Item tooltips on listeners/users/settings, and fill listeners/users/settings *Hint keys across all locale packs. |
||
|
|
0ad79c46af |
fix(share): derive SNI from formal cert when Access SNI is blank
TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip fix(share): derive SNI from formal cert when Access SNI is blank TUIC already fell back to public host / connect host. Now also: - PreferredSNIFromCert / ResolveClientSNI in certutil - AnyTLS + TUIC share use cert SAN/CN when SNI unset - anytls URI export uses same resolution so LE certs verify without skip |
||
|
|
8bf6835ac2 |
fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches
Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. fix(share): AnyTLS skip-cert only when cert is self-signed or host mismatches Do not hardcode insecure=1. Use DecideClientSkipCertVerify so Let's Encrypt (and other formal certs) verify when SNI/public host matches the certificate. |
||
|
|
14889ffc61 |
revert(share): AnyTLS URI back to previous panel format
Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. revert(share): AnyTLS URI back to previous panel format Keep PathEscape password, sni/fp/insecure/allowInsecure and idle-session query params instead of the strict anytls-go official scheme. |
||
|
|
446caa37d4 |
fix(share): AnyTLS URI per official anytls-go scheme
anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) fix(share): AnyTLS URI per official anytls-go scheme anytls://[password@]host[:port]/?sni=...&insecure=1#name - password as URI userinfo (percent-encoded) - only official query keys: sni, insecure - fragment for display name - subscription ExportShare now emits URI (was YAML-only) |
||
|
|
8c5e21adc4 |
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
fix(protocol): use official users[].username for VLESS/VMess (not name)
MetaCubeX VlessUser is {username, uuid, flow}. The previous "name" key is
ignored by mihomo so inboundUser stayed empty and panel showed "-".
username is what connections metadata.inboundUser reports.
|
||
|
|
64417694a9 |
fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser
Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. fix(protocol): set users[].name for VLESS/VMess so Mihomo reports inboundUser Without name, connections API leaves inboundUser empty and the panel cannot attribute VLESS/VMess traffic to a ProxyUser (shows "-" on 节点1). AnyTLS/HY2 already key users by username and were fine. Also set name on Trojan users. |
||
|
|
f26fde0431 |
fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults
- DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure fix(uri): TUIC/HY2 share links for NekoBox — host-aware skip-cert, defaults - DecideClientSkipCertVerify using connect host (IP vs domain vs SAN) - Default congestion_control=bbr, udp_relay_mode=native, alpn=h3 - Default SNI to domain host when unset; emit allow_insecure + allowInsecure |
||
|
|
adc35e3fe9 |
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
fix(tuic): always apply smart skip-cert-verify for v4 and v5 export
- v4 (token) and v5 (uuid) share the same copyTUICOpts tail that calls
applyClientSkipCertVerify last — no longer omit the flag on either path
- Do not copy server-side skip-cert-verify; decide from cert PEM / certstore
- Share/URI path uses DecideClientSkipCertVerify instead of brittle string Contains("3m-ui")
|
||
|
|
dbc3a25507 |
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent Root cause vs user config/sub: - Inbound had autofill UUID only (8398d58a…) - Subscription exported panel admin UUID/password (6c96e7d2…) - Client auth could never match - asUsersMapUUID: union Config users + bound panel UUID→password - Export tuic-v5: prefer panel credentials when bound (not autofill-only) - TUIC client: skip-cert-verify for panel self-signed (config or certstore) |
||
|
|
05bf9a270e |
chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema
Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 chore: align MetaCubeX audit — mihomo v1.19.31, TUIC modes, VMess schema Per wiki.metacubex.one / KIMI audit: - Bump bundled mihomo to v1.19.31 (amd64-v1 / arm64 digests verified) - TUIC: panel keeps tuic-v4|tuic-v5; legacy "tuic" auto-detects token-only→v4 else v5 (YAML type always "tuic" per official inbound docs) - UI: token field only on tuic-v4; tuic-v5 does not accept token in form - VMess listener schema: drop allow-insecure (not in official VMess listener fields) - Docs: version references → v1.19.31 |
||
|
|
b221a2d731 |
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
fix(tuic): unblock v5 listener creation + complete v4 URI params
Audit against official MetaCubeX wiki found 6 TUIC issues. Fixes:
CRITICAL-1 (node/validator.go:150): mapUserProtocols missing 'tuic-v5'
tuic-v5 listeners with wiki-standard 'users: {UUID: pwd}' map were
rejected with 'field users does not accept an object'. This ran
BEFORE validateProtocolSpecific (which would pass), so creating a
tuic-v5 listener via the panel failed at validation time.
Fix: add 'tuic-v5' to mapUserProtocols. tuic-v4 stays out (v4 uses
token, any users on v4 is rejected by schema).
HIGH-2 (node/uri_builders.go:299-313): v4 URI emitted zero query params
tuicURIs v4 path returned 'tuic://token@host:port#name' with NO
alpn / sni / congestion_control / udp_relay_mode / allow_insecure.
Fix: build shared params map ONCE (covers v4 token + v5 uuid paths).
HIGH-3 (protocol/compile_modules.go:141-148): v4 compiler dropped
extra tokens
'token: [T1, T2, T3]' was reduced to 'token: [T1]' at compile time,
silently dropping T2/T3 even though mihomo accepts multi-token v4.
Fix: new allStringTokens() helper preserves every non-empty token.
MEDIUM-4 (node/uri_builders.go): URI query param naming
tuicURIs used hyphen-case (congestion-controller, udp-relay-mode)
but mihomo URI parser expects snake_case. BuildShare already used
snake_case — only the user_sub URI path was wrong.
Fix: map hyphen-case listener keys to snake_case URI keys
(congestion_control, udp_relay_mode, max_udp_relay_packet_size,
bbr_profile, allow_insecure).
MEDIUM-6 (protocol/share_modules.go:633-634): BuildShare skipCert
too aggressive
any cert + empty SNI forced skipCert=true, breaking formal
(Let's Encrypt) cert listeners when operator forgot SNI.
Fix: default SNI to server host; only skipCert for panel self-signed
PEMs (O=3m-ui marker) or explicit skip-cert-verify: true.
LOW-7 (mihomo/config/listener_schema_registry.go:178-182): tuic-v4
schema whitelisted 'users'
v4 is token-only per wiki; symmetric to tuic-v5 omitting 'token'.
Fix: remove 'users' from tuic-v4 Fields.
Tests: 4 new regression tests in node/validator_test.go covering
tuic-v5 map users (accept), tuic-v4 token array (accept),
tuic-v4-with-users (reject), tuic-v5-with-token (reject).
Full suite 23/23 packages PASS.
|
||
|
|
87409bf5e4 |
fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5)
- tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol fix(tuic): hard-split v4 token vs v5 users paths (stop killing v5) - tuic-v5: never prefer leftover token; use Config users or panel UUID/password - tuic-v4: token from Config only - Decode/Share: do not replace v5 users with token credentials - credentialsFromListenerConfig split by protocol |
||
|
|
cd65594294 | fix(tuic): prefer Config token when classifying generic tuic as v4 for share | ||
|
|
2cd92bd1e7 |
fix(tuic): subscription token from Config; formal certs verify
- BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates fix(tuic): subscription token from Config; formal certs verify - BuildShare/Decode: TUIC v4 token only from listener Config, never panel password - listenerToProxies: refuse tuic-v4 without Config token - skip-cert-verify only for panel self-signed (O=3m-ui / ShouldSkipCertVerify), not for operator formal certificates |
||
|
|
236e58cfff | fix: import strings in compile_modules for TUIC token helper | ||
|
|
3f0adba4cd |
fix: TUIC v4 empty token + stop shadowing multi-user protocol creds
- Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds fix: TUIC v4 empty token + stop shadowing multi-user protocol creds - Seed/autofill/compile: empty token [] is missing; mint a real v4 token - Subscription: only prefer Config auth for listener-native protocols (tuic*, ss, snell, sudoku); anytls/shadowquic keep panel user creds |
||
|
|
5f61445354 | chore: gofmt autofill and share_modules | ||
|
|
133adbcdfb |
feat(share): client YAML for all panel listener protocols
Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. feat(share): client YAML for all panel listener protocols Generate Mihomo proxies YAML per MetaCubeX docs (wiki.metacubex.one): - VMess, Snell, Sudoku, AnyTLS, ShadowQUIC, Mieru, TrustTunnel - Hysteria2 now includes ClientYAML alongside URI - Decode extracts snell psk / sudoku key for export YAML-first for protocols without a stable share URI scheme. |
||
|
|
ded3ab3ed7 |
feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML
Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic feat(share): TUIC v4/v5 client URI and Mihomo proxy YAML Align with MetaCubeX inbound (type tuic) and proxies/tuic docs: - v4: tuic://TOKEN@host with token-only client YAML - v5: tuic://uuid:password@host with uuid+password YAML - Decode token[] and UUID map users for export Refs: wiki.metacubex.one config inbound tuic-v4/v5 and proxies/tuic |
||
|
|
a6d32adeae |
fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki
Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. fix(tuic): align v4/v5 seed+autofill+compile with MetaCubeX wiki Inbound docs use type: tuic for both; v4 auth is token[], v5 is users UUID→password. - Seed quick-create with alpn/h3 + congestion bbr; v4 token vs v5 users - Autofill no longer defaults every TUIC to v5 users map - Compile pure v5 strips token (outbound wiki: token is V4-only) Also add GitHub issue templates (bug/feature) and docs contact links. |
||
|
|
d5629d0247 |
security: remove unverified script downloads
security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads security: remove unverified script downloads |
||
|
|
0e5af8a096 |
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. feat(listeners)!: select REALITY targets with server-side checks BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied. |
||
|
|
4a81280b95 |
fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify
- Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB fix(cert): unify self-signed generation, multi-SAN, export skip-cert-verify - Single certutil.GenerateSelfSigned (Org=3m-ui, 10y, DNS+IP SANs) - autofill + config ensure both call certutil; drop duplicate generators - protocol decode uses ShouldSkipCertVerify for all SkipCert fields - Generator/autofill fold PublicHost/AccessSNI into SAN hints - Document listener-certs must be backed up with the DB |
||
|
|
1d439d4136 |
fix(config): strip more client-only keys from listeners; normalize TUIC token
- Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). fix(config): strip more client-only keys from listeners; normalize TUIC token - Do not passthrough grpc-user-agent/ping-interval/client TUIC hints into inbound YAML (official listeners only document grpc-service-name / ws-path). - Export TUIC v4 token as a string for clients (listener uses []string). |
||
|
|
fbca88a534 |
fix(config): align listener/client fields with MetaCubeX wiki (round 2)
Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. |
||
|
|
d393114a3b |
fix(config): align listener/client fields with MetaCubeX wiki
- Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML |
||
|
|
4854f18753 |
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
|
||
|
|
4190024234 |
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
|