1import { ensureSettingsLoaded, getSettings, lock } from "./vault";2import { isRecoveryConfirmPending } from "./recovery-pending";34const AUTO_LOCK_ALARM = "autolock";5const DEFAULT_AUTO_LOCK_MINUTES = 5;6const MIN_IDLE_SECONDS = 15;7let autoLockDeferredUntil = 0;8910export function deferAutoLockForOperation(durationMs: number): () => void {11 const deadline = Date.now() + Math.max(0, durationMs);12 autoLockDeferredUntil = Math.max(autoLockDeferredUntil, deadline);13 return () => {14 if (autoLockDeferredUntil !== deadline) return;15 autoLockDeferredUntil = 0;16 touchAutoLock();17 };18}1920function rescheduleDeferredAutoLock(): boolean {21 const remainingMs = autoLockDeferredUntil - Date.now();22 if (remainingMs <= 0) return false;23 chrome.alarms.create(AUTO_LOCK_ALARM, {24 delayInMinutes: remainingMs / 60_000,25 });26 return true;27}2829function resolveAutoLockMinutes(): number {30 const setting = getSettings().autoLockMinutes;31 if (typeof setting !== "number") return DEFAULT_AUTO_LOCK_MINUTES;32 return setting; 33}3435export function touchAutoLock(): void {36 if (!chrome.alarms?.clear || !chrome.alarms?.create) return;37 chrome.alarms.clear(AUTO_LOCK_ALARM);38 const minutes = resolveAutoLockMinutes();39 if (minutes <= 0) return; 40 chrome.alarms.create(AUTO_LOCK_ALARM, { delayInMinutes: minutes });41}4243export function clearAutoLock(): void {44 if (!chrome.alarms?.clear) return;45 chrome.alarms.clear(AUTO_LOCK_ALARM);46}4748export async function setupAutoLock(): Promise<void> {49 await ensureSettingsLoaded();50 if (!chrome.idle?.setDetectionInterval) return;51 const minutes = resolveAutoLockMinutes();52 const seconds = minutes > 0 ? Math.max(MIN_IDLE_SECONDS, minutes * 60) : MIN_IDLE_SECONDS;53 chrome.idle.setDetectionInterval(seconds);54}5556function broadcastLocked(): void {57 58 chrome.runtime?.sendMessage?.({ type: "VAULT_LOCKED" })?.catch?.(() => {});59 60 61 try {62 chrome.tabs.query({}, (tabs) => {63 for (const tab of tabs) {64 if (tab.id === undefined) continue;65 chrome.tabs.sendMessage(tab.id, { type: "VAULT_LOCKED" }).catch(() => {});66 }67 });68 } catch {69 70 }71}7273if (typeof chrome !== "undefined" && chrome.alarms?.onAlarm?.addListener) {74 chrome.alarms.onAlarm.addListener(async (alarm) => {75 if (alarm.name !== AUTO_LOCK_ALARM) return;76 if (rescheduleDeferredAutoLock()) return;77 if (await isRecoveryConfirmPending()) return;78 await lock();79 broadcastLocked();80 });81}8283if (typeof chrome !== "undefined" && chrome.idle?.onStateChanged) {84 chrome.idle.onStateChanged.addListener(async (state) => {85 if (resolveAutoLockMinutes() <= 0) return;86 if (state !== "idle" && state !== "locked") return;87 if (state === "idle" && rescheduleDeferredAutoLock()) return;88 if (await isRecoveryConfirmPending()) return;89 await lock();90 broadcastLocked();91 });92}