Commit Graph
64 Commits
Author SHA1 Message Date
kazeyukiro 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
2026-09-22 00:40:00 +08:00
kazeyukiro 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.
2026-09-22 00:15:00 +08:00
kazeyukiro 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)
2026-09-21 23:55:00 +08:00
kazeyukiro 37a5fa0284 feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
2026-09-20 23:50:00 +08:00
kazeyukiro 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
2026-09-19 23:15:00 +08:00
kazeyukiro 0c5338db2e fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
fix(vless): do not require username on uuid-mode users
Fixes #79 — creating a VLESS listener failed with
"vless listener users[0] requires username" because autofill only minted
uuid (matching Mihomo) while ValidateNode required a panel username.
- uuid-mode validation (VLESS/VMess): only uuid is required
- autofillUUIDUsers: default username "user" when empty
- EnsureListenerCredentials: backfill username on existing uuid rows
2026-09-18 22:20:00 +08:00
Z User 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.
2026-09-16 14:49:45 +00:00
kazeyukiro 42cd620905 fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
fix(tuic-v4): guarantee non-empty token on create and apply
- credentials.EnsureListenerCredentials: tuic-v4 mints token; tuic-v5 users
- ValidateNode covers tuic-v4/v5; empty token[] is not "configured"
- Autofill calls EnsureListenerCredentials after defaults
- Config generate mints token if tuic-v4 still empty before Mihomo apply
2026-09-16 15:45:00 +08:00
kazeyukiro b1a34e1384 fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
fix(sub): export tuic-v4/v5 in subscription links
ClientURIs only handled protocol "tuic", so tuic-v4/v5 were skipped in
base64/v2ray subscription (silent continue) while single-node URI path
often still worked via other exporters.
- ClientURIs + ClientURIsWithCredentials accept tuic-v4/v5
- Prefer Config token/users for TUIC/SS/snell/… in listenerToProxies
- user.credentialsFromListenerConfig reads TUIC token and tuic-v4/v5 users
2026-09-16 13:25:00 +08:00
Z User a1cbef1d74 fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
fix: UNIQUE/soft-delete hygiene across tokens, HWID, config, templates, node delete
- Hard-delete access tokens and HWID devices so unique indexes free immediately
- Revive soft-deleted HWID rows and visual-config fragments on re-register/upsert
- Align node.Service.Delete with pre-delete name free; Unscoped clone rollbacks
- Clearer template name collision errors
2026-09-10 15:34:34 +00:00
Z User 7e3e0ab7d2 fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
fix(node): fall through share exporters when ClientYAML is empty
mui.BuildShares / protocol.ExportShares could succeed with URIs but empty
ClientYAML; connection-check then aborted with client YAML unavailable and
never reached converter.ExportClientYAML. Prefer any non-empty YAML across
tiers, then legacy converter.
2026-09-09 17:06:59 +00:00
phil d0b53dcc9e feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
feat(listeners): verify client connectivity and expose diagnostics
Inspect listener readiness and test exported client endpoints with isolated Mihomo clients. Preserve public addresses, ports and protocol settings, report diagnostic stages, and repair generated access SNI fields.
2026-09-09 21:50:55 +08:00
Z User 3279d1c963 feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
2026-08-31 06:12:47 +00:00
Z User da5a0f67d1 fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
2026-08-30 15:14:36 +00:00
Z User 0754e6a9d6 fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
2026-08-30 13:04:59 +00:00
Z User e445bcd323 fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
2026-08-30 10:34:48 +00:00
Z User fad6e612a5 fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
2026-08-30 08:30:38 +00:00
Z User c817650597 fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
2026-08-30 04:13:26 +00:00
Z User a379c33159 fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
2026-08-30 00:06:00 +00:00
風雪 58f69e3f9d fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
2026-08-29 09:39:00 +00:00
風雪 0f234c0efe fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
2026-08-29 09:38:25 +00:00
風雪 70af9bcb46 test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
2026-08-29 15:00:42 +08:00
風雪 63b5094d83 fix: export REALITY public keys as raw URL-safe base64 2026-08-29 15:00:33 +08:00
風雪 34c155f83f refactor(share): remark fragment encoding aligned with clients 2026-08-29 13:29:50 +08:00
風雪 d66b803ea6 fix(share): standard URIs for VMess/Trojan/Hy2/SS/TUIC (pbk derive, port, user rows) 2026-08-29 13:24:18 +08:00
風雪 a12c4716af fix(share): derive Reality pbk for standard URIs; fix listen port; clarify autofill UI 2026-08-29 13:08:40 +08:00
風雪 c587ca1217 fix(ci): format node/uri.go after import cleanup 2026-08-29 11:29:32 +08:00
風雪 fc7bdcf526 fix(ci): drop unused imports in node/uri.go 2026-08-29 11:28:26 +08:00
風雪 6bbea65368 fix(ci): remove unused imports in node/api.go 2026-08-29 11:17:20 +08:00
風雪 3fc0503960 feat(node): prefer m-ui BuildShares for URI/client YAML export 2026-08-29 00:30:59 +08:00
風雪 708ffd0471 feat(node): ExportNodeURI via typed protocol registry BuildShare 2026-08-29 00:24:26 +08:00
風雪 e0a0afc577 feat(share): ExportNodeURI (uri/qr/client_yaml) + ExportClientYAML 2026-08-29 00:17:49 +08:00
風雪 f353209a42 fix(share): restore URI builders split file + m-ui Access Profile on ClientURIs 2026-08-29 00:16:53 +08:00
風雪 70862f279e fix(share): restore full uri.go (was truncated) 2026-08-29 00:13:30 +08:00
風雪 ff321e2890 fix(share): restore uri.go + Access Profile + packetEncoding () 2026-08-29 00:12:36 +08:00
風雪 dc62de00a3 feat(share): node share (uri/qr/client_yaml) + Access Profile in URIs 2026-08-29 00:10:35 +08:00
風雪 6cc1c500ba fix: URI export short-id array, Reality sni/fp, VLESS encryption=none 2026-08-24 23:36:16 +08:00
風雪 475c1fc172 style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
2026-08-21 16:40:11 +00:00
風雪 b36df8f029 fix: audit — access-token export uses PublicHost; robust IPv6 URI host 2026-08-20 15:05:21 +00:00
風雪 857f8e7ec5 feat: full IPv6 support for panel, listeners, and share links 2026-08-20 14:44:10 +00:00
風雪 6b3a09a09c update
update
update
update
update
update
update
update
update
update
update
update
2026-08-19 12:49:36 +08:00
風雪 fc00113ea5 fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
2026-08-18 14:00:26 +00:00
風雪 96153d4531 Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
2026-08-18 17:14:11 +08:00
風雪 79fc469e11 feat(node): Access Profile public_host overrides URI export host 2026-08-18 16:58:16 +08:00
風雪 7e80804323 fix: expose node-only routes without duplicate CRUD 2026-08-18 13:48:19 +08:00
風雪 664885ce2a fix: expose node-only routes without duplicate CRUD 2026-08-18 13:47:43 +08:00
風雪 a6523cd610 fix(node): trust pre-resolved host in ClientURIs; host helper lives in uri_host.go 2026-08-18 11:13:10 +08:00
風雪 a73961d077 fix(node): public host helper for share URI export 2026-08-18 11:12:24 +08:00
風雪 a40b339352 chore: remove uri_host.go pending unified host helper in uri.go 2026-08-18 11:12:13 +08:00
風雪 66f799dfb3 fix(node): host resolution for URI export (public_url + loopback fallback) 2026-08-18 11:11:24 +08:00