4dde61e8dbcc8402f4dc245de120f514b1a2dc21
633
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4dde61e8db |
fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs)
HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) fix(frontend): align listener config form with backend schema (hy2 fields + grpc-opts/mekya inputs) HIGH-1: remove max-idle-time from hysteria2 form + set() HIGH-2: remove handshake-timeout from hysteria2 form + set() (kept for sudoku) MEDIUM-1: narrow UDP_PROTOCOLS to ['shadowsocks', 'snell'] — vmess/vless/trojan udp toggle was dead (backend compile_modules.go strips it) MEDIUM-2: add 5 R-M4 grpc-opts client-metadata Form.Items (grpc-user-agent, ping-interval, max-connections, min-streams, max-streams) on vmess/vless/trojan, with formValuesToConfig set() and configToFormValues reads MEDIUM-3: add 2 R-M3 mekya-config client-metadata Form.Items (polling-interval-initial, h2-pool-size) on vmess, with mekya-config builder/reader fields i18n: add 7 new keys + 6 hints to en.ts and zh.ts listeners section Lint PASS (0 errors, 33 pre-existing fast-refresh warnings) Build PASS (tsc -b + vite build OK) |
||
|
|
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. |
||
|
|
6b11dc793e | fix(ui): require Snell obfs host when mode is set | ||
|
|
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. |
||
|
|
19916828e2 | fix(ui): remove stray '(' text node before TUIC protocol section | ||
|
|
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). |
||
|
|
32a3d56061 |
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
fix(sudoku): remove required validation from key field
The sudoku key field had rules={[{ required: true }]} which blocked
form submission when the operator left it empty. But the backend
autofill (autofill.go:74-80) automatically generates a 32-byte
base64 key when empty — the same pattern as snell PSK, SS password,
and TUIC token.
Fix: removed required rule, added tooltip 'Leave empty to auto-generate'.
This was the root cause of 'sudoku cannot create' — the form refused
to submit without a key, but the operator didn't know to fill one in
(and shouldn't need to).
|
||
|
|
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 ✅ |
||
|
|
02f1b6ef24 |
fix(frontend): actually apply TUIC v4/v5 split to frontend
Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) fix(frontend): actually apply TUIC v4/v5 split to frontend Previous commit 20d47e8 only modified backend files — frontend Listeners.tsx and ListenerConfigFields.tsx were not included due to a file copy error. This commit applies the frontend changes: - Listeners.tsx: PROTOCOLS array splits 'tuic' into 'tuic-v4'/'tuic-v5' - ListenerConfigFields.tsx: - ALWAYS_TLS_PROTOCOLS includes tuic-v4/tuic-v5 - Form condition: protocol === 'tuic' || 'tuic-v4' || 'tuic-v5' - case 'tuic': includes tuic-v4 and tuic-v5 fallthrough - token field: only shows for tuic-v4 and tuic (backward compat) - tuic-v5: no token field (uses panel-managed users) |
||
|
|
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
|
||
|
|
3c8969812c | fix(ui): filter XHTTP out of capability transport for non-VLESS | ||
|
|
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) |
||
|
|
313164131d |
fix(ui): use full ListenerConfigFields instead of reduced capability form
useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). fix(ui): use full ListenerConfigFields instead of reduced capability form useCapabilityForm was hardcoded true, so create/edit node only showed the thin schema-driven CapabilityFormFields and hid protocol sections (ShadowQUIC jls-upstream, Reality details, etc.). |
||
|
|
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. |
||
|
|
9a7370cc96 |
chore(i18n): remove unused auto-generate field guide strings
Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. chore(i18n): remove unused auto-generate field guide strings Drop autoGenerateHint, field guide titles, per-protocol guide blocks, and password/reality auto tooltips from zh/en after UI simplification. |
||
|
|
76da8746e1 |
ui(listeners): drop auto-generate prose; use placeholder auto
Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". ui(listeners): drop auto-generate prose; use placeholder auto Remove field-guide alerts and tooltips about auto-generation. SS password, Snell PSK, REALITY key/short-id keep placeholder "auto". |
||
|
|
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. |
||
|
|
5b8e42dfc1 |
feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only
Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. feat(ui): per-protocol required/optional/auto field guide; XHTTP VLESS-only Show a unified field guide alert for each protocol. Keep XHTTP out of VMess/Trojan transport options and document that on the transport control. |
||
|
|
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)
|
||
|
|
dbec0b3099 |
fix(scripts): install/update/uninstall port handling
Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> |