importScripts("crypto-store.js"); let masterKey = null; // 解锁后持有,锁定或 SW 重启后清空 let autoLockTimer = null; const AUTO_LOCK_MS = 10 * 60 * 1000; // 10 分钟无操作自动锁定 chrome.runtime.onInstalled.addListener(() => { chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }) .catch((err) => console.warn("[AutoLogin] 设置 sidePanel 行为失败:", err)); chrome.sidePanel.setOptions({ panelWidth: 340 }) .catch((err) => console.warn("[AutoLogin] 设置 sidePanel 宽度失败:", err)); migrateLegacyVault(); console.log("[AutoLogin] 扩展已安装"); }); chrome.action.onClicked.addListener((tab) => { if (tab?.id !== undefined) { chrome.sidePanel.open({ tabId: tab.id }).catch(() => {}); } }); // 旧版明文数据迁移:把 loginConfigs 转为 environments 明文结构 async function migrateLegacyVault() { const data = await chrome.storage.local.get(["environments", "loginConfigs", "vaultMeta"]); if (data.vaultMeta) return; if (Array.isArray(data.environments) && data.environments.length > 0) return; if (Array.isArray(data.loginConfigs) && data.loginConfigs.length > 0) { const envs = [{ id: "env_legacy", name: "默认", configs: data.loginConfigs }]; await chrome.storage.local.set({ environments: envs }); await chrome.storage.local.remove("loginConfigs"); console.log("[AutoLogin] 旧版 loginConfigs 已迁移为明文 environments"); } } // 无 vault 明文模式:确保 session 有 environments(从 local 加载或创建预设) async function ensurePlainEnvironments() { if (await CryptoStore.hasVault()) return; // 加密模式不处理 const data = await chrome.storage.local.get("environments"); let envs = data.environments; if (!Array.isArray(envs) || envs.length === 0) { const PRESET = ["个人", "测试", "生产"]; envs = PRESET.map((name) => ({ id: "env_" + Date.now().toString(36) + Math.random().toString(36).slice(2, 8), name, configs: [], })); await chrome.storage.local.set({ environments: envs }); } const session = await chrome.storage.session.get("environments"); if (!session.environments) { await chrome.storage.session.set({ environments: envs, activeEnvId: envs[0]?.id || null, }); } } // SW 启动即初始化明文环境到 session,供 content script 自动登录读取 ensurePlainEnvironments().catch((err) => console.warn("[AutoLogin] 启动初始化失败:", err)); function resetAutoLockTimer() { if (autoLockTimer) clearTimeout(autoLockTimer); if (masterKey) { autoLockTimer = setTimeout(() => { console.log("[AutoLogin] 闲置超时,自动锁定"); doLock(); }, AUTO_LOCK_MS); } } async function doLock() { masterKey = null; if (autoLockTimer) { clearTimeout(autoLockTimer); autoLockTimer = null; } await CryptoStore.lock(); } // session 中 environments 变化时用内存密钥重新加密写回 local chrome.storage.onChanged.addListener(async (changes, areaName) => { if (areaName !== "session") return; if (!changes.environments) return; const environments = changes.environments.newValue; if (!environments) return; // 锁定时被清除,无需持久化 try { if (masterKey) { await CryptoStore.persistEncrypted(environments, masterKey); } else { // 无 vault 明文模式:明文回写 local await chrome.storage.local.set({ environments }); } } catch (err) { console.warn("[AutoLogin] 持久化失败:", err); } }); chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { (async () => { try { switch (message.action) { case "getVaultStatus": { const hasVault = await CryptoStore.hasVault(); if (!hasVault) { await ensurePlainEnvironments(); sendResponse({ hasVault: false, unlocked: true, pendingImport: false }); break; } const unlocked = !!masterKey; sendResponse({ hasVault, unlocked, pendingImport: false }); break; } case "setupVault": { // 设置口令:若已有明文 environments 则加密它,否则创建预设 const localData = await chrome.storage.local.get("environments"); let initialEnvs; if (Array.isArray(localData.environments) && localData.environments.length > 0) { initialEnvs = localData.environments; } else { const PRESET = ["个人", "测试", "生产"]; initialEnvs = PRESET.map((name) => ({ id: "env_" + Date.now().toString(36) + Math.random().toString(36).slice(2, 8), name, configs: [], })); } masterKey = await CryptoStore.setupVault(message.password, initialEnvs); await chrome.storage.local.remove("environments"); // 已加密,明文不再需要 resetAutoLockTimer(); sendResponse({ success: true }); break; } case "unlock": { try { const { key } = await CryptoStore.unlock(message.password); masterKey = key; resetAutoLockTimer(); sendResponse({ success: true }); } catch (err) { sendResponse({ success: false, error: err.message }); } break; } case "lock": { await doLock(); sendResponse({ success: true }); break; } case "getActivity": { sendResponse({ unlocked: !!masterKey, autoLockMs: AUTO_LOCK_MS, }); break; } case "ping": { // 任何消息都视为用户活动,顺带重置自动锁定计时 resetAutoLockTimer(); sendResponse({ pong: true }); break; } default: sendResponse({ error: "unknown action" }); } } catch (err) { sendResponse({ success: false, error: err.message }); } })(); return true; // 异步响应 });