4dde61e8dbcc8402f4dc245de120f514b1a2dc21
422
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fbca88a534 |
fix(config): align listener/client fields with MetaCubeX wiki (round 2)
Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. fix(config): align listener/client fields with MetaCubeX wiki (round 2) Complete field-level audit against https://wiki.metacubex.one/ for 8 protocols (shadowsocks/vmess/vless/trojan/hysteria2/tuic-v4/tuic-v5/sudoku). HIGH (8): - VLESS listener: strip client-only `encryption` field (server uses `decryption`) - mux-option: drop undocumented `brutal-opts` from all 9 listener schemas (keep `brutal` map) - vmess/vless/trojan listener: drop fabricated top-level `ws-headers` (client uses ws-opts.headers) - 3m-ui share: nest ws-opts.Host under headers map per proxies-transport - hysteria2 listener: drop `handshake-timeout`/`max-idle-time` (client/TUIC only) - m-ui hysteria2Listener: drop 6 quic-go fields (cwnd/udp-mtu/initial-stream-receive-window/...) - tuic-v5 listener: drop `token` (v4-only per wiki) - sudoku listener: drop httpmask.path_root/tls/host/multiplex (wiki uses dash path-root only) MEDIUM (11): - VMess listener: strip top-level `alterId` (per-user form in users[] only) - VMess/VLESS/Trojan listener: drop undocumented top-level `udp` - SS kcptun: emit plugin:kcptun + plugin-opts from kcp-tun block (m-ui + converter paths) - m-ui hysteria2ClientProxy: add ports/hop-interval/obfs-min/obfs-max/name-cert-verify/fingerprint/handshake-timeout - m-ui hysteria2RealmConfig: drop client-side `proxy` (listener-only) - m-ui classicClientProxy (VMess/Trojan): add global-padding/authenticated-length/fingerprint/name-cert-verify/tlsmirror-opts/smux - m-ui vlessClientProxy: add fingerprint/name-cert-verify/smux - m-ui websocketClient: add headers map (was only path) - converter TUIC v4+v5: add ip + name-cert-verify copy - converter mekya-opts: add polling-interval-initial + h2-pool-size - converter hysteria2: add ports/hop-interval/obfs-min-packet-size/obfs-max-packet-size - converter applyClientWrappers: add tlsmirror-opts branch LOW: - Update TestGenerateListenersUsesModelTLS to assert wiki-correct VLESS (no top-level tls) - SS client: add udp-over-tcp/udp-over-tcp-version/ip-version/smux (both paths) - grpc-opts: add grpc-user-agent/ping-interval/max-connections/min-streams/max-streams (both paths) - ech-opts: pass-through in copyClientTLS (both paths) - Schema whitelist: add mekya-config.polling-interval-initial/h2-pool-size + grpc-opts 5 fields (client-only metadata accepted by panel; mihomo ignores unknown listener fields) Verification: - go build ./... → PASS - go vet ./... → clean - go test ./... → 16/16 packages PASS Refs: wiki-audit-1 (33 findings) + wiki-audit-2 (4 R-M follow-ups) in worklog. |
||
|
|
d393114a3b |
fix(config): align listener/client fields with MetaCubeX wiki
- Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML fix(config): align listener/client fields with MetaCubeX wiki - Client SS type is "ss" (not listener name shadowsocks) - Drop TUIC/Hy2 server-only keys from client export - Strip simple-obfs enable from SS plugin-opts - Do not emit top-level tls on VLESS/VMess/Trojan listeners - Strip client-only keys (sni, skip-cert-verify, *-opts) from listener YAML |
||
|
|
18a8572530 |
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
fix(tls): durable per-listener certs on disk across panel updates
Self-signed PEMs that only lived in ephemeral YAML were re-minted on every
upgrade, invalidating all client trust. Store certificate/private-key under
/var/lib/3m-ui/listener-certs/{id}.crt|.key, restore into config when DB
lacks a pair, and never rotate a complete pair already on disk or in DB.
|
||
|
|
a607c6a4f4 |
fix(tls): respect allow-insecure; only persist listener config when changed
Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. fix(tls): respect allow-insecure; only persist listener config when changed Forcing a self-signed cert and clearing allow-insecure broke nodes that intentionally run TLS-off behind nginx/caddy. Skip cert injection when allow-insecure is true. Avoid rewriting every listener row on each apply. |
||
|
|
01a638ba04 |
fix(config): do not fail entire apply when one listener is invalid
A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. fix(config): do not fail entire apply when one listener is invalid A single bad listener (e.g. Snell obfs-opts without Host) previously aborted GenerateFinalConfig, so Mihomo could not load any node after panel update. Skip broken listeners, log them, and still emit the rest. |
||
|
|
9353b94dad |
fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t
Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. fix(snell): strip incomplete obfs-opts (missing Host) before Mihomo -t Mihomo rejects obfs-opts without Host. Normalize mode+host, drop incomplete blocks before and after compile, persist cleaned config, and require host in the form when mode is selected. |
||
|
|
9724185d05 |
fix(snell): drop incomplete obfs-opts missing host/mode
Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. fix(snell): drop incomplete obfs-opts missing host/mode Mihomo rejects listeners with obfs-opts that omit Host. Only emit the block when both mode and host are set, and sanitize partial blocks on save/config generation. |
||
|
|
9c1d714aa0 |
fix(tuic): cert autofill + client export for tuic-v4/tuic-v5
Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. fix(tuic): cert autofill + client export for tuic-v4/tuic-v5 Panel protocol kinds tuic-v4/tuic-v5 were missing from TLS ensure paths, so self-signed certs were not injected. Client export only matched "tuic" and emitted invalid type tuic-v4/v5. Normalize export type to tuic and restore UDP support for hy2/shadowquic/tuic variants. |
||
|
|
c742c36bcf |
fix(tls): persist autofilled self-signed certs to listener DB
Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. fix(tls): persist autofilled self-signed certs to listener DB Runtime ensureListenerTLSMaterial minted a new cert pair on every config generation when the DB row had no certificate. Panel updates/reloads then rotated server identity and broke clients that verify TLS (or pinned fingerprints). Write the filled certificate/private-key back to the listener config once so subsequent reloads stay stable. |
||
|
|
273d1f7019 |
fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion
Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). fix(trojan+reality/mieru): SNI sync + mieru TLS exclusion Two issues fixed: == Trojan+Reality: subscription missing SNI == copyClientTLS derives 'servername' from reality-config.server-names but trojan client proxy uses 'sni' (not 'servername'). The trojan case only copyOption'd 'sni' (which was stripped by sanitizeServerConfig), and the fallback check (sni==nil && servername==nil) was short- circuited because servername was already set from reality. Fix: at the end of copyClientTLS, if sni is empty but servername has a value, copy servername → sni. This ensures all protocols that use 'sni' (trojan, hysteria2, tuic, etc.) get the correct TLS hostname from reality server-names, jls dest, or other wrapper sources. == Mieru: client YAML has invalid TLS fields == Mieru is a plain TCP/UDP proxy — no TLS at all. But copyClientTLS was called for mieru (not in the exclusion list), injecting tls:true, sni, skip-cert-verify etc. from any certificate that might be present in the listener config. Mihomo rejects these fields on mieru proxy. Fix: added 'mieru' to the copyClientTLS exclusion list alongside 'shadowsocks' and 'shadowquic' (which also skip copyClientTLS). |
||
|
|
3c6e7b5f86 |
fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback
ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) fix(shadowquic): remove TLS cert injection, skip copyClientTLS, SNI fallback ShadowQUIC uses QUIC's built-in TLS — it does NOT need certificate/private-key (not in official listener schema) and does NOT need tls:true/skip-cert-verify in the client proxy (not in official client proxy schema). Three issues fixed: 1. Removed shadowquic from protocolNeedsServerCertificate (autofill.go) and listenerProtocolNeedsCert (tls_ensure.go). These functions were injecting self-signed certificates into the listener config, but the ShadowQUIC schema has no certificate field → Mihomo rejects: 'field certificate is not supported for listener protocol shadowquic' 2. Skip copyClientTLS for shadowquic (converter/client.go). QUIC has built-in TLS; the client proxy doesn't need tls:true, certificate, or skip-cert-verify fields. copyClientTLS was setting these based on the injected (now removed) certificate. 3. Added SNI fallback to server host. When jls-upstream is absent or has no sni/addr, the client YAML had no SNI → TLS handshake fails. Now falls back to the server address as SNI (same fix as trojan/hy2). Official ShadowQUIC client proxy fields: type, server, port, username, password, sni, alpn, quic-versions, zero-rtt, congestion-controller, up, down, cwnd, bbr-profile, max-datagram-frame-size, max-open-streams, recv-window-conn, recv-window, disable-mtu-discovery, udp-over-stream, keep-alive-interval (NO tls, NO certificate, NO skip-cert-verify) |
||
|
|
18655e32c5 |
fix(mieru): remove certificate/private-key from mieru listener
Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. fix(mieru): remove certificate/private-key from mieru listener Mieru is a TCP/UDP proxy that does NOT use TLS — it has no certificate/private-key fields in the official Mihomo listener schema. But ensureServerTLSCertificate and ensureListenerTLSMaterial both listed mieru as needing a cert, so they injected self-signed PEMs into the listener config. Mihomo rejected with: listener 'mieru': field 'certificate' is not supported Fix: removed 'mieru' from the protocol list in both: - autofill.go: protocolNeedsServerCertificate - tls_ensure.go: listenerProtocolNeedsCert Mieru now correctly skips TLS certificate generation. |
||
|
|
83be2eeeba |
fix(trojan/hysteria2): SNI missing in client export — fallback to server host
ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ fix(trojan/hysteria2): SNI missing in client export — fallback to server host ROOT CAUSE: listener config strips 'sni' in sanitizeServerConfig (autofill.go:116) because 'sni' is a client-only hint, not a Mihomo listener field. But the client YAML export (converter/client.go) reads 'sni' from the listener config to populate the client proxy's 'sni' field. With 'sni' stripped, the exported client YAML had no SNI at all. For Trojan, this means the client doesn't know which hostname to verify in the TLS certificate → TLS handshake fails. Fix: in the trojan and hysteria2 cases of listenerToProxies, if sni and servername are both empty after copyOption, fall back to the server host address as the SNI. This matches what most clients do implicitly when no SNI is configured. Also checked other protocols: - vmess/vless: copyClientTLS already has reality/jls fallback logic ✅ - anytls: copyClientTLS called in base, has fallback ✅ - tuic: ensureTUICClientDefaults + copyOption sni ✅ - trusttunnel: copyOption sni in client list ✅ |
||
|
|
4854f18753 |
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
feat: split TUIC into TUIC v4 and TUIC v5 in protocol selector
The protocol dropdown now shows 'TUIC v4' and 'TUIC v5' as separate
options instead of a single 'tuic'. This makes it clear which
authentication mode the listener uses:
- TUIC v4: token-based auth (token: ["..."])
- TUIC v5: UUID+password auth (users: {UUID: PASSWORD})
Implementation:
- Frontend: PROTOCOLS array splits 'tuic' into 'tuic-v4' and 'tuic-v5'
Select shows them as separate options. Token field only shows for v4.
- Backend: tuic-v4 and tuic-v5 are accepted as valid protocol names
in schema registry, compiler registry, autofill, and mihomo listener
protocol list. Generator normalizes tuic-v4/tuic-v5 to 'tuic' for
Mihomo (which only has one 'tuic' type).
- Compiler: TUICCompiler gets a 'kind' field. tuic-v4 compiler ensures
token is present and removes users. tuic-v5 compiler uses users map.
- Existing 'tuic' protocol still works (backward compatible).
- autofill: tuic-v4 and tuic-v5 both call autofillTUICUsers (which
correctly handles token-vs-users logic).
Verification: go build/vet/test PASS, npm run build PASS.
|
||
|
|
4190024234 |
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
fix(tuic): token field must be slice not string
Same class of bug as trusttunnel network: Mihomo expects TUIC v4 token
as an array (token: ["TOKEN"]), but the frontend stored a single
token as a string. Mihomo rejected with 'token' is not a slice.
Fix:
- Frontend: token always stored as array (even when single token)
- Backend: TUICCompiler converts string token to []string{token}
for legacy configs
Also audited all other array-type fields:
- alpn: Select mode=tags → array ✅
- quic-versions: Select mode=tags → array ✅
- short-id: Select mode=tags → array ✅
- server-names: Select mode=tags → array ✅
- network (trusttunnel): mode=multiple → array ✅ (fixed in prev commit)
- token (tuic v4): now always array ✅ (this fix)
No other type mismatches found.
|
||
|
|
156b21fcc1 |
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
fix(trusttunnel): network field must be slice not string
Mihomo expects network: ["tcp", "udp"] (array) for TrustTunnel
listeners. The frontend Select stored a single string ("tcp" or
"udp"), which copyConfigPassthrough emitted as network: "tcp"
(string). Mihomo rejected with: 'network' is not a slice.
Fix:
- Frontend: network Select changed to mode="multiple" (multi-select)
Storing as array, reading as array (backward compatible with string)
- Backend: TrustTunnelCompiler.Compile converts string network to
[]string{network} for legacy configs that still have a string
Official docs: network: ["tcp", "udp"] # http2+http3
|
||
|
|
0e2d47d778 |
fix(protocol): XHTTP transport is VLESS-only in capabilities and UI
VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. fix(protocol): XHTTP transport is VLESS-only in capabilities and UI VMess/Trojan shared transportComponents() which listed XHTTP. Split a VLESS-only transportComponentsWithXHTTP(); hide XHTTP radio/hint for other protocols and refuse to emit xhttp-config unless protocol is vless. |
||
|
|
214605d9c8 |
fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror
- Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) fix(ui/protocol): P1 always-TLS UX, P2 wrapper sanitize, P3 ShadowQUIC/tlsmirror - Hy2/TUIC/AnyTLS/TrustTunnel: no Security=None; always show cert with auto hint - Optional protocols: cert only when security_layer=tls - Do not emit incomplete shadow-tls/res-tls/jls/jls-upstream/tlsmirror - Sanitize same blocks on save and config generation - ShadowQUIC default congestion-controller=cubic - VMess minimal tlsmirror-config (dest + primary-key) |
||
|
|
d46ad2a94e |
fix(listener): drop incomplete jls-upstream before Mihomo validate
Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. fix(listener): drop incomplete jls-upstream before Mihomo validate Empty jls-upstream (missing addr) fails mihomo -t on ShadowQUIC. Require addr on the form and sanitize at save/generation. |
||
|
|
dacc5f5b08 | fix(tls): autofill regenerates when only cert or key exists | ||
|
|
4e532fa93b |
fix(tls): regenerate full cert pair when only key or cert is present
Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. fix(tls): regenerate full cert pair when only key or cert is present Half-filled TLS material blocked autofill and left TUIC/AnyTLS without a usable certificate. Clear the partial pair and issue a new self-signed certificate+key together. |
||
|
|
e589f9d414 |
fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill
TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. fix(tuic): client uuid fallback, ALPN h3 defaults, real UUID autofill TUIC v5 clients require uuid+password matching server users map keys. Fill uuid from username when panel UUID is empty, default alpn=h3 and congestion-controller=bbr, auto skip-cert-verify for panel certs, and stop using the non-UUID key "default" in autofill. |
||
|
|
d6e64ab313 |
chore(release): set version to v1.0.0
Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. chore(release): set version to v1.0.0 Align Makefile, embedded default, frontend package, and script help text with the first stable release tag. |
||
|
|
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. |
||
|
|
a19a34420a |
fix(anytls): always inject TLS cert; clear allow-insecure
Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). fix(anytls): always inject TLS cert; clear allow-insecure Incomplete jls-config no longer suppresses self-signed cert generation. When certificate/private-key are filled, drop allow-insecure so clients can dial normal AnyTLS+TLS (not nginx offload mode). |
||
|
|
8f9ffb1a08 |
fix(listener): strip incomplete jls-config before Mihomo validate
Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. fix(listener): strip incomplete jls-config before Mihomo validate Empty or half-filled jls-config (missing dest/users) causes mihomo -t to fail. Require complete JLS on the form; sanitize on save and at config generation. |
||
|
|
de6425ae86 |
fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC
Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. fix(listener): auto-fill TLS certificate for Trojan/Hy2/AnyTLS/TUIC Mihomo rejects listeners with unset certificate/private-key. Expand autofill beyond Hysteria2, run on update as well as create, and ensure material at config generation so existing DB rows still pass mihomo -t. |
||
|
|
4b00a1268a |
fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic
Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. fix(functional): batch autofill, soft-delete name reclaim, hasCredState test, sub_token error, batch reset traffic Deep functional audit of node/user/subscription/traffic features found 5 bugs. All fixed. All tests pass (including the previously failing hasCredState test). == CRITICAL == F1: BatchCreate skips AutofillListenerDefaults Batch-created listeners had no auto-generated UUIDs, passwords, REALITY keys, SS ciphers, snell PSKs, or sudoku keys → mihomo rejected the config → entire batch failed. Fix: call AutofillListenerDefaults before ValidateModel in loop. F2: BatchCreate doesn't reclaim soft-deleted names Inline Count check used GORM default scope (excludes soft-deleted) but UNIQUE index covers them → DB constraint error on name clash. Fix: use ensureUniqueName which renames soft-deleted rows. F3: Failing test contradicts hasCredState fallback fix Test asserted no fallback when hasCredState=true + empty creds. But we intentionally removed the guard to fix 'unset fields: users'. Fix: updated test to assert config users ARE included as fallback. == HIGH == F4: sub_token generation ignores error subTok, _ := randomHex(16) — empty sub_token on rand.Read failure. Fix: check error, return on failure. F5: BatchResetTraffic doesn't trigger config regeneration Over-quota users stayed blocked for ~10s after traffic reset. Fix: added notifyCredentialsChanged() after reset. Verification: go build/vet/test all PASS. gofmt clean. |
||
|
|
5b9674987f |
fix(backup): restore mihomo-config.yaml from backup zip
Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase fix(backup): restore mihomo-config.yaml from backup zip Backup zip contains 3m-ui.db + mihomo-config.yaml + backup-meta.txt. RestoreDatabase only extracted 3m-ui.db — mihomo-config.yaml was silently dropped. After restoring a backup, the mihomo config file on disk was stale (from before the backup was taken). Fix: - extractDBFromZip now returns both dbContent and mihomoCfg - RestoreDatabase takes mihomoCfgPath parameter - After restoring the DB, also writes mihomo-config.yaml if the zip contained it and the path is configured - Mihomo config write failure does NOT fail the whole restore (DB is already restored; operator can manually restore config) - api.go passes h.mihomoCfg to RestoreDatabase |
||
|
|
913783b309 |
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
fix(critical): listener users empty when panel creds unavailable
ROOT CAUSE: asUsersArray/asUsersMap/asUsersMapUUID had a guard:
if hasCredState { return nil }
When a listener had ListenerUser bindings (hasCredState=true) but the
panel credentials were empty (decrypt failure, user inactive, etc.),
the compiler returned nil users → Mihomo config had no users field →
validation failed: 'unset fields: users'.
This caused two symptoms:
1. Subscription returns 'no exportable proxies for user'
2. Binding nodes fails: 'Mihomo configuration could not be updated:
validate Mihomo configuration: listener 1 has unset fields: users'
Fix: removed the hasCredState guard in all three functions. When panel
credentials are empty, fall back to the listener config's users field.
This is safe because:
- Config users were validated by the listener schema
- Config users were autofilled (password/UUID generated) on create
- Panel users take precedence when available (fromCreds checked first)
- Config users are a safety net for decrypt failures, inactive users
The hasCredState parameter is kept in the signature for API compat
but no longer affects the fallback logic.
|
||
|
|
090d81605e |
fix(subscription): return actual error message instead of generic 'failed'
The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. fix(subscription): return actual error message instead of generic 'failed' The generic 'subscription generation failed' gave users no clue what was wrong. Now the actual error is returned in the JSON response: - 'user is not bound to any listener' → bind the user to a node - 'no exportable proxies for user' → check listener config / protocol - 'failed to load credentials' → check credential_key / user passwords - 'listener X requires at least one active user' → bind active users The log.Printf is still present for server-side diagnostics. |
||
|
|
6698073cd4 |
fix(subscription): decrypt failure no longer breaks all users' subscriptions
ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. fix(subscription): decrypt failure no longer breaks all users' subscriptions ROOT CAUSE: ActiveCredentialsByListener returned an error if ANY user's password decrypt failed (e.g. after credential_key rotation or version upgrade). This caused ALL users' subscriptions to return 422, even users whose passwords were perfectly fine. The error propagated through: ActiveCredentialsByListener → error → userBoundListeners → error → GenerateUserRawConfig / GenerateUserBase64Subscription → error → subscription.go handler → 422 Unprocessable Entity Fix: when decryptPassword fails for one user, skip that user and continue processing others. The affected user's subscription will still fail (no matching credential → 'no exportable proxies'), but all other users' subscriptions work normally. Operators should reset the affected user's password after a credential_key rotation to restore their subscription. |
||
|
|
f14e95b684 |
fix(all-remaining): 24 audit findings — Medium + Low severity
All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. fix(all-remaining): 24 audit findings — Medium + Low severity All remaining unfixed issues from 3-round exhaustive audit are now resolved. 8 Medium + 16 Low = 24 items. == Medium (8) == M1: GetLogs timestamp always time.Now() mihomo/service.go GetLogs now parses RFC3339 prefix from stored log lines, infers level (ERROR/WARN/INFO/DEBUG) from payload prefix. M2: Cron parser silently ignores */N and range telegram/scheduler.go cronFieldMatches now supports */N (step), A-B (range), A-B/N (stepped range) in addition to * and comma. M3: findExistingProcesses holds pm.mu during /proc scan mihomo/process.go start() now calls findExistingProcesses() BEFORE acquiring pm.mu. Logs/Status/Stop no longer blocked during scan. M4: Cluster HealthCheckAll sequential (N*12s) cluster/service.go now fans out goroutines with WaitGroup. Worst case drops from N*12s to ~12s. M5: Panel settings PUT not transactional router/panel_settings.go PUT handler now wraps create/update loop in db.Transaction(). Partial failure rolls back. M6: Cluster api_token no validation at save time cluster/service.go Create/Update now validate JWT shape (starts with 'ey', 3 dot-separated parts). Clear error message guides operator to POST /api/v1/auth/login. M7: Disk full — stale config warning not prominent app/app.go soft-fail warnings changed to [WARNING] prefix + hint to check listener configs. M8: Telegram bot retries forever on 401 telegram/bot.go loop now detects 401/Unauthorized, switches to 5-minute retry interval (was 5s). Clears on success. == Low (16) == L1: Scheduler/Bot Start() idempotent via sync.Once L2: Container.Shutdown() method added L3: Enforcer lastBlocked prunes deleted users L4: traffic.Service first-call rate skipped (was bogus spike) L5: strings.HasPrefix replaces path[:4]=="/api" L6: ActiveCredentialsByListener batch-load (N+1→1 query) L7: Telegram bot commands check DB errors L8: Cluster health save error logged L9: Collector continues on AddSample failure (was return) L10: user.Create logs warning instead of returning error after successful DB write L11-L14: Documentation comments for known limitations (HTTP-01 goroutine, GlobalConfig thread-safety, credentialsChanged thread-safety, SubToken TOCTOU) L15: useAuth.ts calls fetchMe() to refresh mustChangePassword L16: Verified access-tokens/client-access endpoints are NOT dead Verification: go build/vet/test PASS, npm run build PASS, gofmt clean. |
||
|
|
76c81b8261 |
fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields
Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. fix(audit-r3): traffic rule/chains/start fields, ProxyUser telegram fields Round 3: frontend-backend API contract audit found 2 issues. Fixed. F-1 (Medium): Traffic page rule column always empty Frontend Traffic.tsx declares a 'rule' column on connections, but backend ConnectionView (traffic/types.go) didn't include Rule/Chains/ Start fields. Mihomo's /connections API returns these (api/types.go Connection struct has Rule, Chains, Start) but the collector dropped them when building ConnectionView. Fix: added Rule/Chains/Start to ConnectionView struct; collector now populates them from conn.Rule/conn.Chains/conn.Start. F-2 (Low): ProxyUser type missing telegram_id/telegram_name Backend SafeUser returns telegram_id + telegram_name (added in Telegram enhancement), but frontend ProxyUser interface didn't declare them. Also had phantom created_at (backend never returns it). Fix: replaced created_at with telegram_id + telegram_name in frontend/src/api/users.ts ProxyUser interface. Verification: go build/vet PASS, go test PASS, npm run build PASS. |
||
|
|
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. |
||
|
|
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
|
||
|
|
266b59bee1 |
fix(backup): RestoreDatabase now handles zip format (the actual backup format)
ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works fix(backup): RestoreDatabase now handles zip format (the actual backup format) ROOT CAUSE: ExportBackup produces a .zip file (3m-ui-backup-*.zip containing 3m-ui.db + mihomo-config.yaml + backup-meta.txt). But RestoreDatabase treated the uploaded file as a raw SQLite database — it io.Copy'd the entire zip file into the DB path without extracting. On restart, GORM/SQLite opened the zip file as a DB, found it wasn't a valid SQLite format, and the panel failed to start. This is why 'restoring backup and restarting 3m-ui' made the panel unable to boot — the DB file was actually a zip archive. Fix: RestoreDatabase now: 1. Reads the upload into memory (128 MiB limit enforced by API handler) 2. Checks the PK\x03\x04 zip magic bytes 3. If zip: extracts 3m-ui.db from the archive via zip.NewReader 4. If not zip: treats as raw SQLite DB (backward compatible) 5. Writes extracted DB content to the temp file + atomic rename This fixes both scenarios: - User downloads .zip backup → uploads it for restore → now works - User has a raw .db file → uploads it for restore → still works |
||
|
|
7addcdc5c7 |
fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup
Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK fix(non-listener): enforcement retry, DB restore warning, security headers, config placeholder, sensitive key gaps, dead UI options, bot API server, update.sh dedup Non-listener comprehensive audit found 4 Medium + 4 Low issues. All fixed. VLESS+REALITY and listener schema untouched. == Medium == M-NEW-C1: Enforcement doesn't retry failed config regen traffic/enforcement.go CheckAndEnforce updated lastBlocked BEFORE calling RegenerateConfig. If regen failed, lastBlocked was already set, so next tick saw no change and never retried — over-quota users stayed connected. Fix: update lastBlocked only after successful regen; preserve old state on failure for retry. M-NEW-C2: DB restore orphans running process's SQLite handle system/api.go RestoreDatabase renames the DB file, but the running panel keeps writing to the old (unlinked) inode. Added prominent [WARNING] log + restart_required:true + *** RESTART REQUIRED *** message in response. In-place GORM reconnect not feasible; restart is the correct approach. M-NEW-G1: Backend doesn't send CSP/security HTTP headers CSP was only in index.html meta tag. Added SecurityHeaders() middleware setting X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: same-origin, X-XSS-Protection: 1; mode=block on all responses. CSP NOT set on API responses (meta CSP handles the SPA shell). M-NEW-A1: Default config.yaml has placeholder secrets backend/config/config.yaml contained DefaultJWTSecret and DefaultCredentialKey (rejected by Validate → startup failure for developers). Replaced with CHANGE_ME placeholders + comments explaining use install.sh or openssl rand -hex 32. == Low == L-NEW-B1: isSensitiveSettingKey heuristic gaps panel_settings.go blocklist missing 'key' and 'auth' substrings. Added (api deliberately excluded — too broad). L-NEW-D1: enabled_events UI has dead options Settings.tsx Select included node_down/node_up/block/unblock which have no backend effect. Removed. Kept only implemented events: login/cpu/memory/crash/expiry/traffic. L-NEW-D3: Bot loop hardcodes api.telegram.org bot.go getUpdates/deleteWebhook hardcoded the official Telegram API URL. Now takes apiBase parameter; loop() passes tgClient.apiBase() so custom api_server setting is respected for long-polling. L-NEW-H1: update.sh duplicate CONFIG_DIR Line 11-12 had CONFIG_DIR defined twice. Removed duplicate. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 16 packages all PASS - npm run build : PASS - gofmt : clean - sh -n update.sh : OK |
||
|
|
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)
|
||
|
|
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
|
||
|
|
19842c8cf3 |
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(client): SS plugin wrappers + VMess mkcp/mekya transport export
Final re-audit found 3 Medium-severity client config export bugs.
All fixed. No VLESS+REALITY code paths touched.
== N1+N2: SS+shadow-tls/res-tls/jls-config client YAML wrong format ==
The 3m-ui converter emitted VMess-style shadow-tls-opts/restls-opts/
jls-opts for SS, and set tls:true (SS has no tls field). The m-ui
bridge decodeSS didn't populate spec.Security so the m-ui SS module's
plugin emission never fired.
Fix (converter/client.go):
- Guard copyClientTLS to skip for SS (no tls/sni/servername/alpn)
- New applySSPluginWrappers emits documented plugin format:
- shadow-tls: plugin=shadow-tls, plugin-opts={version,password,host}
- restls: plugin=restls, plugin-opts={host,password,version-hint,restls-script}
- jls: plugin=jls, plugin-opts={host,username,password,alpn}
- client-fingerprint defaults chrome (respects listener config)
Fix (mui/bridge.go):
- decodeSS now populates spec.Security via decodeSSSecurity helper
(shadow-tls→ShadowTLS, res-tls→ResTLS, jls-config→JLS)
- Added decodeShadowTLSConfig/decodeResTLSConfig/decodeJLSConfig helpers
- m-ui SS module's existing shadowsocksPlugin emission now fires
== N3: VMess+mkcp/mekya client YAML missing transport ==
copyTransport only handled ws-path/grpc-service-name/xhttp-config.
VMess+mkcp/mekya client YAML defaulted to TCP.
Fix (converter/client.go copyTransport):
- mkcp-config→mkcp-opts: direct field copy (mtu/tti/uplink-capacity/
downlink-capacity/congestion/write-buffer/read-buffer/seed/header)
- mekya-config→mekya-opts: kcp sub-block 1:1; max-write-size→
max-request-size; max-write-duration-ms→max-write-delay
(URL left empty — no listener counterpart, operator sets manually)
Fix (mui/bridge.go decodeHandler):
- mkcp-config→VMessHandlerMKCP + h.MKCP population
(consumed by compileClassicClient→mkcp-opts)
- mekya-config noted as gap (no Mekya handler domain type; converter
handles it for the 3m-ui native path)
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
|
||
|
|
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)
|
||
|
|
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. |
||
|
|
3b61cd45e3 |
fix(listeners): complete snell res-tls fields + unify anytls users as opaque
Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. fix(listeners): complete snell res-tls fields + unify anytls users as opaque Continued the shadow-tls/res-tls/jls-config nested field audit against the official Mihomo wiki. == Fix 1: snell res-tls was missing 3 fields == snell's res-tls only listed 4 fields (enable, dest, password, rate-limit) while ss/vmess/trojan all list 7. Mihomo uses the same ResTLS struct for all protocols, so snell supports the full set. Added: restls-script, min-record-len, proxy. Now all 6 protocols with res-tls (shadowsocks, snell, vmess, vless, trojan, anytls) have the identical 7-field res-tls schema: enable, dest, password, restls-script, min-record-len, proxy, rate-limit == Fix 2: anytls shadow-tls.users / jls-config.users unified to opaque == anytls decomposed users into .users.name/.users.password (shadow-tls) and .users.username/.users.password (jls-config), while all other protocols treat users as an opaque child. This inconsistency was workable after C2 (validator now handles arrays of nested objects), but the decomposition served no purpose and diverged from the canonical pattern. Unified to opaque 'users' child matching ss/snell/vmess/vless/trojan. == Field audit summary (shadow-tls / res-tls / jls-config) == All 6 protocols now have identical nested schemas: shadow-tls: enable, version, password, users, handshake.dest, handshake.proxy res-tls: enable, dest, password, restls-script, min-record-len, proxy, rate-limit jls-config: enable, users, dest, sni, alpn, proxy, rate-limit Verification: go build/vet/test all PASS; gofmt clean. |
||
|
|
f434b6293a |
fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields
Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean |
||
|
|
126e70dbd1 |
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
fix(listeners): deep audit fixes — TUIC users, array validation, VLESS encryption, sudoku/snell autofill
Comprehensive audit of the entire listener config pipeline found and
fixed 7 bugs across autofill, validation, compilation, and schema.
== Critical (broke Mihomo) ==
C1: TUIC listener with no panel users produced empty 'users' field
autofillTUICUsers wrote users as ARRAY [{username, password}], but
the TUIC compiler (asUsersMapUUID) only reads MAP form. Compiled
output had no users → Mihomo rejected. Fixed: autofill now writes
v5 map form {'default': '<pass>'}.
C2/C3/C4: Validator rejected array-typed nested fields
anytls shadow-tls.users, anytls jls-config.users, and vmess
tlsmirror-config.embedded-traffic-generator.steps are ARRAYS of
objects in Mihomo, but the schema decomposed them into .name/
.password/.host children, making the parent require a JSON object.
Fixed: validateListenerObject now type-switches on the value —
arrays of objects are recursively validated element-by-element
against the same nested schema. Handles []interface{} and
[]map[string]interface{}.
== High (wrong config output) ==
H1: VLESS 'encryption' field silently stripped by compiler
copyConfigPassthrough had 'encryption' in its strip list (intended
to drop the client-side hint), but 'encryption' is also a legitimate
VLESS server field paired with 'decryption'. Removed it from the
strip list; panel-only keys (_-prefixed, access_profile,
transport_layer, security_layer) remain stripped.
H2: Sudoku listener created without 'key' was unusable
Sudoku uses top-level 'key' for auth (no users). Autofill had no
case for sudoku. Added: auto-generates 32-byte base64 key + defaults
aead-method to chacha20-poly1305.
H3: Snell listener created without 'version' may be rejected
Autofill set psk but never version. Added: defaults version to 4
(current Mihomo default) when unset, without clobbering pre-existing
numeric versions.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean
|
||
|
|
9a3674685c |
fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki
Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) fix(listeners): align TUIC v5 users map + TrustTunnel users injection with wiki Continued the listener schema audit against the official Mihomo wiki (https://wiki.metacubex.one/config/inbound/listeners/). Found and fixed three remaining inconsistencies after the previous commit (11e8d4b). == 1. TUIC v5 users format (was: array, should be: map) == Mihomo wiki TUIC v5 example: users: UUID1: PASSWORD1 UUID2: PASSWORD2 The TUICCompiler was using asUsersArray (producing [{username,password}]), which is wrong for v5. Added asUsersMapUUID helper that emits map{uuid: password} (key=UUID, falling back to Username for legacy panel users without UUID). TUICCompiler.Compile now: - Passes through (TUIC v4) via copyConfigPassthrough. - When no is configured, emits v5 map-form users via asUsersMapUUID. == 2. TrustTunnel credential injection (was: missing) == TrustTunnel was registered as GenericCompiler{kind:"trusttunnel"}, which does NOT inject in.Users into the compiled config — so credentials stored in the panel DB never reached Mihomo. Created dedicated TrustTunnelCompiler that calls asUsersArray (TrustTunnel uses users: [{username, password}] per wiki). Updated DefaultCompileRegistry to use it. == 3. Sudoku missing mux-option == Mihomo wiki sudoku example shows mux-option (commented). Added mux-option to sudoku Fields + NestedFields in the schema registry so the validator accepts it. == Audit summary (all protocols vs wiki) == shadowsocks: cipher + password (top-level) ✅ correct snell: psk + version ✅ correct vmess: users: [{username, uuid, alterId}] ✅ correct vless: users: [{username, uuid, flow}] ✅ correct (excluded per user) trojan: users: [{username, password}] ✅ correct (fixed in 11e8d4b) anytls: users: {username: password} ✅ correct (fixed in 11e8d4b) mieru: users: {username: password} ✅ correct (fixed in 11e8d4b) hysteria2: users: {username: password} ✅ correct (fixed in 11e8d4b) tuic-v4: token: [str] ✅ correct (passthrough) tuic-v5: users: {UUID: PASSWORD} ✅ correct (fixed this commit) shadowquic: users: [{username, password}] ✅ correct trusttunnel: users: [{username, password}] ✅ correct (fixed this commit) sudoku: key (no password) + mux-option ✅ correct (mux-option added this commit) |
||
|
|
90f67a6b1d |
fix(listeners): align auth field formats with Mihomo official listener schemas
Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) fix(listeners): align auth field formats with Mihomo official listener schemas Root cause of 'listener hy2: field password is not supported for listener protocol hysteria2': autofillPasswordUsers created a top-level 'password' field for protocols that use 'users' (map or array) or 'token'/'key' for authentication instead. Verified all listener protocols against https://wiki.metacubex.one/ (config/inbound/listeners/*) and fixed three classes of bugs. == autofill.go: protocol-specific user autofill == Split the single autofillPasswordUsers (which created top-level 'password' for 8 protocols) into three helpers matching Mihomo schemas: - autofillUsersMap → hysteria2/anytls/mieru (users: {name: pass}) - autofillUsersArray → trojan/shadowquic/trusttunnel (users: [{name, pass}]) - autofillTUICUsers → tuic (keeps existing token for v4; defaults to v5 users array if neither token nor users set) - Removed sudoku from the password autofill switch entirely — it uses 'key' (top-level), not password/users. - Deleted the old autofillPasswordUsers function. == compile.go + compile_modules.go: users format == asUsersArray always returned []map (array), but hysteria2/anytls/mieru require map{username: password}. Added asUsersMap helper. Created dedicated AnyTLSCompiler + MieruCompiler (replacing GenericCompiler registrations) that emit map-form users. Hysteria2Compiler.Compile now calls asUsersMap. Trojan/ShadowQUIC/TUIC compilers unchanged (their array format already matches Mihomo docs: users: [{username, password}]). == listener_schema_registry.go: missing mux-option == Added mux-option to hysteria2 and tuic Fields + NestedFields — both are shown (commented) in the official Mihomo wiki examples. == Protocol → auth format reference (verified against wiki) == shadowsocks: cipher + password (top-level) ✅ unchanged snell: psk (top-level) ✅ unchanged vmess: users: [{username, uuid, alterId}] ✅ unchanged vless: users: [{username, uuid, flow}] ✅ unchanged (excluded) trojan: users: [{username, password}] ✅ fixed (was: top-level password) anytls: users: {username: password} ✅ fixed (was: top-level password) mieru: users: {username: password} ✅ fixed (was: top-level password) hysteria2: users: {username: password} ✅ fixed (was: top-level password) tuic-v4: token: [str] ✅ fixed (was: top-level password) tuic-v5: users: [{username, password}] ✅ fixed (was: top-level password) shadowquic: users: [{username, password}] ✅ fixed (was: top-level password) trusttunnel: users: [{username, password}] ✅ fixed (was: top-level password) sudoku: key (top-level, no password) ✅ fixed (was: in password autofill) |
||
|
|
dc13e69951 |
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean |
||
|
|
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. |