4dde61e8dbcc8402f4dc245de120f514b1a2dc21
167
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) |
||
|
|
6b11dc793e | fix(ui): require Snell obfs host when mode is set | ||
|
|
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. |
||
|
|
19916828e2 | fix(ui): remove stray '(' text node before TUIC protocol section | ||
|
|
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).
|
||
|
|
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) |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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)
|
||
|
|
fac3d88929 |
fix(settings): port change now shows explicit restart warning
Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. fix(settings): port change now shows explicit restart warning Problem: Changing the panel port in Settings → Panel/NAT only saved to config.yaml and updated in-memory cfg.Server.Port, but the HTTP server kept listening on the old port. The success toast said 'restart service to apply' but was easy to miss — users expected the port change to take effect immediately. Root cause: the HTTP server (gin r.Run) binds once at startup to cfg.Server.Port. Changing the port in-memory doesn't rebind. A panel restart is required. The response included restart_required:true and a message, but the frontend only showed a generic success toast. Fix: when the port actually changes (prevPort != newPort), show a Modal.warning with: - old port → new port - explicit 'systemctl restart 3m-ui' command - new access URL http://IP:newPort When only listen/public_url changes (port unchanged), keep the existing success toast. |
||
|
|
fad6e612a5 |
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
|
||
|
|
f434b6293a |
fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields
Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean fix(listeners): transport options per protocol + clean autofill hint + remove dead hy2 fields Second-round audit against https://wiki.metacubex.one/config/inbound/ found and fixed 4 issues: == 1. XHTTP transport option shown for trojan/vmess (frontend) == Official Mihomo docs explicitly state: 'xhttp: 仅 VLESS 支持 xhttp 传输层,请勿在其他协议上使用' 'mkcp: 仅 VMess 支持 mKCP 传输层' 'mekya: 仅 VMess 支持 Mekya 传输层' The transport_layer Radio.Group showed TCP/ws/grpc/xhttp for ALL protocols in TRANSPORT_PROTOCOLS (vmess/vless/trojan). Wrapped the xhttp Radio.Button in {XHTTP_PROTOCOLS.has(protocol) && ...} so it only appears for vless. TCP/ws/grpc remain shared. mekya/mkcp for vmess already render via dedicated EnableSection blocks (unchanged). == 2. Autofill hint was SS/Snell-centric (frontend i18n) == The global autoGenerateHint Alert mentioned only 'REALITY/SS/Snell/Hy2' but the autofill logic now covers ALL protocols (sudoku key, snell version, trojan/hy2/anytls/mieru/tuic/shadowquic/trusttunnel users). Updated zh+en i18n strings to enumerate all autofilled fields so the hint is consistent and accurate regardless of which protocol form is open. == 3. hysteria2 dead fields obfs-min/max-packet-size (backend+frontend) == These fields are NOT in the Mihomo hysteria2 listener source (appear copied from hysteria v1). Removed from: - schema registry Fields allowlist (backend) - ListenerConfigFields.tsx FORM_OWNED_KEYS + set() calls + Form.Item - mui/protocol/hysteria2.go struct fields + struct literals - mui/domain/node.go Hysteria2Spec fields Kept max-idle-time + handshake-timeout (present in Mihomo source, just wiki-undocumented). Kept obfs/obfs-password (salamander, wiki-documented). == 4. trojan ss-option verified (no change) == Confirmed present in Mihomo trojan listener source (wraps trojan in a shadowsocks layer). Real feature, wiki-undocumented. Kept as-is. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : 15 packages all PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean |
||
|
|
dc13e69951 |
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean feat(telegram): full bot enhancement with inline menus, cron reports, events Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/ Field naming follows existing 3m-ui snake_case convention (not sanaei's tg* prefix) per project maintainer's request. == Data layer == - ProxyUser: add TelegramID (indexed) + TelegramName fields for linking proxy users to their Telegram accounts (self-service queries). - SafeUser + ToSafeUser: expose both new fields. - user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods. - user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram (registered before /:id to avoid path capture). - UpdateInput/CreateInput: accept TelegramID + TelegramName. == Settings expansion (8 new fields, snake_case) == - schedule: cron expr or @daily/@every 6h for periodic reports (default @daily) - attach_backup: include DB backup zip in periodic report - language: bot message language zh/en (default zh) - enabled_events: comma-sep event list (default 'login,cpu,crash') Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic - expiry_warn_days: remind N days before expiry (0=off) - traffic_warn_gb: remind when remaining traffic < N GB (0=off) - proxy_url: socks5:// or http:// proxy for Telegram API - api_server: custom Bot API server (empty=official) - EventEnabled(name) helper for per-event gating. == Client enhancements == - Proxy support: http(s):// via http.Transport.Proxy; socks5:// via golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback. - Custom API server (apiBase() replaces hardcoded URL). - SendDocument: multipart sendDocument for backup file attachment. - GetMe + SetMyCommands: for bot-info + set-my-commands endpoints. - sendWithKeyboard: sendMessage with reply_markup (inline keyboards). - answerCallbackQuery: clear callback loading spinner. == Bot commands + inline menus == - /id: reply with sender's Telegram numeric ID. - /usage: admin → search users; bound user → self-query traffic/expiry/sub URL. - /start + /help: send inline keyboard menu (admin menu for admin chats, user menu for bound users, plain text for unbound). - Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/ backup/restart) in 4 rows. - User menu: my_usage + my_sub buttons. - callback_query handling: answerCallbackQuery + dispatch on callback_data. - Access control: admin chats always pass; non-admin chats pass only when FromID matches a ProxyUser.TelegramID. - Bot struct: added userSvc field for GetByTelegramID lookups. - NewBot signature: NewBot(db, mihomoSvc, userSvc). == Cron scheduler (new telegram/scheduler.go) == - Periodic report goroutine driven by Settings.Schedule. - Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron. - Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted counts. - Optional backup: AttachBackup → system.WriteZip → SendDocument. - Settings reload on every tick (no restart needed for schedule changes). - NotifyEvent(event, details): generic event emitter for one-shot alerts. == Events layer == - login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure). Failure path added to auth/api.go Login handler. Both gated by EventEnabled('login') — admins can mute success spam yet keep failure alerts. - memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as shared 'resource warn %' threshold. 1-hour cooldown dedup. - crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash. Fires on non-zero exit while desired==true (unexpected crash, not admin stop). Wired in app/container.go. - Dual thresholds: expiry (hours + days), traffic (percent + GB) with separate dedup keys so neither suppresses the other. == API endpoints == - POST /telegram/set-my-commands: registers 12-command menu with Telegram. - GET /telegram/bot-info: returns bot username/first_name/id. == Frontend == - telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands + fetchTelegramBotInfo API functions. - Settings.tsx: 8 new form controls (schedule Input, language Select, enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb InputNumber, attach_backup Switch, proxy_url Input, api_server Input). Added 'Set bot commands' button calling setTelegramCommands. - i18n: 11 new keys (zh + en) for the new settings labels. == Verification == - go build ./... : PASS - go vet ./... : PASS - go test ./... : all 15 packages PASS - npm run build (tsc + vite) : PASS, 3241 modules - gofmt : clean |
||
|
|
2f3856704b |
fix(frontend): local QR generation, JWT expiry, CSP, axios CVE
- H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. fix(frontend): local QR generation, JWT expiry, CSP, axios CVE - H-1: Subscription URIs / sub_tokens were sent to the third-party api.qrserver.com via GET query, leaking SS passwords / VMess UUIDs / sub_tokens to an untrusted service. Replace with a new QRCode.tsx component using the 'qrcode' npm package (pure client-side canvas). Remove the QR <img> from the backend subpage defaultHTML too. - H-2: Add isTokenExpired() helper parsing JWT exp; useAuth now proactively logs out when the token has already expired instead of waiting for a 401. Full httpOnly-cookie migration documented as a follow-up (requires backend API changes). - MED-2: axios ^1.7.9 -> ^1.8.4 (CVE-2025-27152). - MED-3: Add CSP, X-Frame-Options: DENY, X-Content-Type-Options, referrer=same-origin meta tags to index.html. - MED-6: Remove leftover console.log(r.data) in Settings.tsx. - MED-7: Commit package-lock.json for reproducible builds (npm ci). - LOW-1: Simplify keep_token to !values.bot_token (consistent with Cluster.tsx). - LOW-2: Remove dead share Modal + state in Users.tsx. - LOW-6: Unify formatBytes in utils/format.ts (4 duplicates removed). - LOW-7: ChangePassword min length 6 -> 8. |
||
|
|
1b497d09ff | fix(sub): serve HTML page for target=html without subconverter | ||
|
|
a88e7e581f | fix(i18n): move share strings inside export default (CI tsc) | ||
|
|
fbf5f6df27 | fix(i18n): move share strings inside export default (CI tsc) | ||
|
|
ad6d2b4ecf | feat(ui): unified Share/Subscription page (links + node URIs) | ||
|
|
9a88f64849 | feat(ui): unified Share/Subscription page (links + node URIs) | ||
|
|
94fd22b657 | feat(ui): unified Share/Subscription page (links + node URIs) | ||
|
|
1c4bbd30da | feat(ui): unified Share/Subscription page (links + node URIs) | ||
|
|
396cd6427d | feat(ui): unified Share/Subscription page (links + node URIs) | ||
|
|
da07d85f14 | feat(ui): unified Share/Subscription page (links + node URIs) | ||
|
|
e017d40b35 | feat(ui): unified Share/Subscription page (links + node URIs) | ||
|
|
2a63bed00e |
i18n: autofill and reality key hints
i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints |
||
|
|
f7c5e6109e |
i18n: autofill and reality key hints
i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints i18n: autofill and reality key hints |
||
|
|
f909238e57 | fix(share): derive Reality pbk for standard URIs; fix listen port; clarify autofill UI | ||
|
|
4ffca2ef4b | feat(nat): custom panel port/listen/public_url via env, API, settings UI, install.sh | ||
|
|
f52207df5d | feat(nat): custom panel port/listen/public_url via env, API, settings UI, install.sh | ||
|
|
a18429b169 | feat(nat): custom panel port/listen/public_url via env, API, settings UI, install.sh | ||
|
|
43099ea84d |
i18n: auto-generate hints for create node
i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node |
||
|
|
deee84ccc3 |
i18n: auto-generate hints for create node
i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node i18n: auto-generate hints for create node |
||
|
|
7628696f76 | feat(ui): create-node auto-generate secrets (REALITY/password/psk); relax required fields | ||
|
|
53cccdedb8 | feat(ui): create-node auto-generate secrets (REALITY/password/psk); relax required fields | ||
|
|
02ecc231e7 | feat: remove quick-setup; autofill secrets on create + generate helper | ||
|
|
c5dbac1510 | feat: remove quick-setup; autofill secrets on create + generate helper | ||
|
|
3faf7227d4 | feat: remove quick-setup; autofill secrets on create + generate helper |