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.
118 lines
3.9 KiB
Go
118 lines
3.9 KiB
Go
package app
|
|
|
|
import (
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/config"
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/listener"
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/mihomo"
|
|
dbconfig "github.com/kazeyukiro/3m-ui/backend/internal/mihomo/config"
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/node"
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/router"
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/system"
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/telegram"
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/traffic"
|
|
"github.com/kazeyukiro/3m-ui/backend/internal/user"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type Container struct {
|
|
DB *gorm.DB
|
|
Config *config.Config
|
|
Mihomo *mihomo.Service
|
|
Listener *listener.Service
|
|
Node *node.Service
|
|
User *user.Service
|
|
Traffic *traffic.Service
|
|
TrafficCollector *traffic.Collector
|
|
TrafficScheduler *traffic.Scheduler
|
|
System *system.Service
|
|
ConfigEngine *dbconfig.ConfigEngine
|
|
TelegramBot *telegram.Bot
|
|
TelegramScheduler *telegram.Scheduler
|
|
}
|
|
|
|
func NewContainer(db *gorm.DB, cfg *config.Config) *Container {
|
|
mihomoSvc := mihomo.NewService(cfg)
|
|
// Wire crash notification: when the mihomo process exits unexpectedly
|
|
// (non-zero exit while desired==true), emit a Telegram alert.
|
|
mihomoSvc.SetCrashHandler(func(exitErr error) {
|
|
telegram.NotifyCrash(db, exitErr)
|
|
})
|
|
listenerSvc := listener.NewService(db, cfg.Mihomo.Config, mihomoSvc)
|
|
nodeSvc := node.NewService(db, cfg.Mihomo.Config, mihomoSvc)
|
|
nodeSvc.SetRegenerator(listenerSvc)
|
|
userSvc := user.NewService(db)
|
|
systemSvc := system.NewService()
|
|
userSvc.SetCredentialsChangedHandler(func() error {
|
|
return nodeSvc.RegenerateConfig()
|
|
})
|
|
|
|
trafficSvc := traffic.NewService()
|
|
userTraffic := traffic.NewUserService(db)
|
|
collector := traffic.NewCollectorFromDefaults(db, trafficSvc, userTraffic)
|
|
enforcer := traffic.NewEnforcer(db, nodeSvc)
|
|
scheduler := traffic.NewScheduler(collector, enforcer, 0)
|
|
scheduler.SetNotifier(telegram.NewNotifier(db))
|
|
scheduler.Start()
|
|
|
|
tgBot := telegram.NewBot(db, mihomoSvc, userSvc)
|
|
tgBot.Start()
|
|
|
|
tgScheduler := telegram.NewScheduler(db, mihomoSvc, userSvc, systemSvc, cfg.Database.Path, cfg.Mihomo.Config)
|
|
tgScheduler.Start()
|
|
|
|
return &Container{
|
|
DB: db,
|
|
Config: cfg,
|
|
Mihomo: mihomoSvc,
|
|
Listener: listenerSvc,
|
|
Node: nodeSvc,
|
|
User: userSvc,
|
|
Traffic: trafficSvc,
|
|
TrafficCollector: collector,
|
|
TrafficScheduler: scheduler,
|
|
System: systemSvc,
|
|
ConfigEngine: dbconfig.NewConfigEngine(db),
|
|
TelegramBot: tgBot,
|
|
TelegramScheduler: tgScheduler,
|
|
}
|
|
}
|
|
|
|
func (c *Container) RouterDeps() router.Deps {
|
|
return router.Deps{
|
|
DB: c.DB,
|
|
Config: c.Config,
|
|
Mihomo: c.Mihomo,
|
|
Traffic: c.Traffic,
|
|
TrafficCollector: c.TrafficCollector,
|
|
User: c.User,
|
|
Node: c.Node,
|
|
Listener: c.Listener,
|
|
System: c.System,
|
|
}
|
|
}
|
|
|
|
// Shutdown gracefully stops the background goroutines spawned by NewContainer
|
|
// (traffic scheduler, Telegram bot long-poll loop, Telegram scheduler). It is
|
|
// safe to call even when some components are nil. The HTTP server itself is
|
|
// not stopped here — callers should signal/interrupt the server first (or
|
|
// rely on the process exiting) and then invoke Shutdown to release goroutines.
|
|
//
|
|
// Note: this method is currently NOT wired to OS signals; it exists so that
|
|
// future signal-handling code (or tests) can call it. Each Start() is also
|
|
// idempotent via sync.Once, so calling Stop() on a never-started component is
|
|
// still well-defined for the traffic/telegram schedulers and bot.
|
|
func (c *Container) Shutdown() {
|
|
if c == nil {
|
|
return
|
|
}
|
|
if c.TrafficScheduler != nil {
|
|
c.TrafficScheduler.Stop()
|
|
}
|
|
if c.TelegramBot != nil {
|
|
c.TelegramBot.Stop()
|
|
}
|
|
if c.TelegramScheduler != nil {
|
|
c.TelegramScheduler.Stop()
|
|
}
|
|
}
|