package com.jovan.assistant.security import com.jovan.assistant.data.AssistantState import com.jovan.assistant.data.FirebaseRepo import com.jovan.assistant.data.Prefs import com.jovan.assistant.data.WakeStatus import com.jovan.assistant.service.AssistantAccessibilityService /** * Protective layer. Two independent counters inside a sliding window: * - SUSPICIOUS (unauthenticated command, restricted-command attempt): 3 in 60s -> lock + block * - ERROR (repeated action failures): 8 in 60s -> lock + block * While blocked, no voice command is executed. Lifting the block in the UI requires the account password. */ object SecurityGuard { enum class Severity { SUSPICIOUS, ERROR } private const val WINDOW_MS = 60_000L private const val BLOCK_MS = 5 * 60_000L private const val MAX_SUSPICIOUS = 3 private const val MAX_ERRORS = 8 private val suspicious = ArrayDeque() private val errors = ArrayDeque() fun isBlocked(): Boolean = System.currentTimeMillis() < Prefs.blockedUntil @Synchronized fun report(reason: String, severity: Severity = Severity.SUSPICIOUS) { val now = System.currentTimeMillis() val q = if (severity == Severity.SUSPICIOUS) suspicious else errors val max = if (severity == Severity.SUSPICIOUS) MAX_SUSPICIOUS else MAX_ERRORS q.addLast(now) while (q.isNotEmpty() && now - q.first() > WINDOW_MS) q.removeFirst() FirebaseRepo.log("SECURITY", reason, if (severity == Severity.SUSPICIOUS) "warn" else "info") if (q.size >= max) trigger("Too many ${severity.name.lowercase()} events: $reason") } private fun trigger(reason: String) { Prefs.blockedUntil = System.currentTimeMillis() + BLOCK_MS AssistantState.wakeStatus.value = WakeStatus.BLOCKED suspicious.clear(); errors.clear() AssistantAccessibilityService.instance?.lockScreen() FirebaseRepo.log("SECURITY", "PROTECTIVE BLOCK: $reason. Screen locked, commands blocked for 5 min.", "critical") } /** Call only after the password has been re-verified. */ fun clearBlock() { Prefs.blockedUntil = 0L suspicious.clear(); errors.clear() FirebaseRepo.log("SECURITY", "Protective block lifted by user", "info") } }