package jwtauth import ( "context" "log/slog" "time" "commilitia.net/cdrop/internal/db" ) // DeviceSweepInterval is how often the device sweeper wakes up. const DeviceSweepInterval = 1 * time.Hour // RunDeviceSweeper prunes the devices table on a timer so it stays aligned with // the session list (AUTH.md §4): it drops (1) devices whose last_seen is older // than ttl — registration must not outlive the longest valid refresh_token // (brief §2: 196h sliding window) — and (2) browser devices whose web_session is // gone (revoked or expired), which would otherwise linger until the stale cutoff // now that users can no longer remove devices by hand. Native and shortcut // devices keep no web_session and are pruned by the stale cutoff only. ttl ≤ 0 // disables the sweeper. func RunDeviceSweeper(ctx context.Context, queries *db.Queries, ttl time.Duration) { if ttl <= 0 { slog.Info("device sweeper disabled (ttl <= 0)") return } slog.Info("device sweeper running", "ttl", ttl, "interval", DeviceSweepInterval) t := time.NewTicker(DeviceSweepInterval) defer t.Stop() for { select { case <-ctx.Done(): return case <-t.C: now := time.Now() cutoff := now.Add(-ttl).Unix() if err := queries.DeleteStaleDevices(ctx, cutoff); err != nil { slog.Error("device sweeper failed", "err", err) } if _, err := queries.DeleteOrphanBrowserDevices(ctx, now.Unix()); err != nil { slog.Error("device sweeper: orphan browser cleanup failed", "err", err) } } } }