Files
3m-ui/backend/internal/app/container.go
T
Z User 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.
2026-08-31 00:19:24 +00:00

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()
}
}