From 2dbce0d83b19a6adb127d7659f7094b417962f81 Mon Sep 17 00:00:00 2001 From: "yinjun.chen1" Date: Wed, 16 Sep 2026 16:12:52 +0800 Subject: [PATCH] no message --- background.js | 33 ++++++++++++++++++++--- content.js | 73 +++++++++++++++++++++++++++------------------------ 2 files changed, 68 insertions(+), 38 deletions(-) diff --git a/background.js b/background.js index 9f905ba..cdf6d48 100644 --- a/background.js +++ b/background.js @@ -57,6 +57,7 @@ async function ensurePlainEnvironments() { // SW 启动即初始化明文环境到 session,供 content script 自动登录读取 ensurePlainEnvironments().catch((err) => console.warn("[AutoLogin] 启动初始化失败:", err)); +autoRestoreUnlock().catch((err) => console.warn("[AutoLogin] 自动恢复解锁失败:", err)); function resetAutoLockTimer() { @@ -73,6 +74,23 @@ async function doLock() { masterKey = null; if (autoLockTimer) { clearTimeout(autoLockTimer); autoLockTimer = null; } await CryptoStore.lock(); + await chrome.storage.session.remove("__autoPwd"); +} + +// SW 重启后自动恢复解锁:从 session 取已存密码解锁 vault +async function autoRestoreUnlock() { + try { + if (!(await CryptoStore.hasVault())) return; + if (masterKey) return; + const { __autoPwd } = await chrome.storage.session.get("__autoPwd"); + if (!__autoPwd) return; + const { key } = await CryptoStore.unlock(__autoPwd); + masterKey = key; + resetAutoLockTimer(); + console.log("[AutoLogin] 自动恢复解锁成功"); + } catch (err) { + await chrome.storage.session.remove("__autoPwd").catch(() => {}); + } } // session 中 environments 变化时用内存密钥重新加密写回 local @@ -102,11 +120,18 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { const hasVault = await CryptoStore.hasVault(); if (!hasVault) { await ensurePlainEnvironments(); - sendResponse({ hasVault: false, unlocked: true, pendingImport: false }); + const local = await chrome.storage.local.get("environments"); + const sess = await chrome.storage.session.get("environments"); + const cfgCount = (arr) => (arr || []).reduce((s, e) => s + (e.configs?.length || 0), 0); + sendResponse({ + hasVault: false, unlocked: true, pendingImport: false, + localEnvs: (local.environments || []).length, localCfgs: cfgCount(local.environments), + sessEnvs: (sess.environments || []).length, sessCfgs: cfgCount(sess.environments), + }); break; } - const unlocked = !!masterKey; - sendResponse({ hasVault, unlocked, pendingImport: false }); + if (!masterKey) await autoRestoreUnlock(); + sendResponse({ hasVault, unlocked: !!masterKey, pendingImport: false }); break; } @@ -125,6 +150,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { })); } masterKey = await CryptoStore.setupVault(message.password, initialEnvs); + await chrome.storage.session.set({ __autoPwd: message.password }); await chrome.storage.local.remove("environments"); // 已加密,明文不再需要 resetAutoLockTimer(); sendResponse({ success: true }); @@ -135,6 +161,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { try { const { key } = await CryptoStore.unlock(message.password); masterKey = key; + await chrome.storage.session.set({ __autoPwd: message.password }); resetAutoLockTimer(); sendResponse({ success: true }); } catch (err) { diff --git a/content.js b/content.js index 76e18b1..3dbc1de 100644 --- a/content.js +++ b/content.js @@ -1,6 +1,16 @@ const t = (key, ...args) => chrome.i18n.getMessage(key, args) || key; +function showDiag(msg) { + try { + const el = document.createElement("div"); + el.textContent = "[AutoLogin] " + msg; + el.style.cssText = "position:fixed;top:10px;right:10px;z-index:2147483647;background:#1a1a2e;color:#e94560;padding:8px 12px;border-radius:6px;font-size:12px;font-family:monospace;max-width:90vw;word-break:break-all;box-shadow:0 2px 8px rgba(0,0,0,.4)"; + (document.body || document.documentElement).appendChild(el); + setTimeout(() => el.remove(), 10000); + } catch {} +} + async function safeStorageGet(area, keys) { try { return await chrome.storage[area].get(keys); @@ -378,64 +388,55 @@ function attemptKey(envId, domain) { } async function getDomainAttempts(envId, domain) { - const key = attemptKey(envId, domain); - const data = await safeStorageGet("local", "loginAttempts"); - const attempts = data.loginAttempts || {}; - return attempts[key] || { count: 0, lastAttempt: 0 }; + const resp = await chrome.runtime.sendMessage({ action: "getDomainAttempts", envId, domain }).catch(() => null); + return resp?.attempts || { count: 0, lastAttempt: 0 }; } async function incrementDomainAttempts(envId, domain) { - const key = attemptKey(envId, domain); - const data = await safeStorageGet("local", "loginAttempts"); - const attempts = data.loginAttempts || {}; - const cur = attempts[key] || { count: 0, lastAttempt: 0 }; - cur.count += 1; - cur.lastAttempt = Date.now(); - attempts[key] = cur; - await safeStorageSet("local", { loginAttempts: attempts }); - return cur; + const resp = await chrome.runtime.sendMessage({ action: "incrementDomainAttempts", envId, domain }).catch(() => null); + return resp?.attempts || { count: 0, lastAttempt: 0 }; } async function resetDomainAttempts(envId, domain) { - const key = attemptKey(envId, domain); - const data = await safeStorageGet("local", "loginAttempts"); - const attempts = data.loginAttempts || {}; - if (attempts[key]) { - delete attempts[key]; - await safeStorageSet("local", { loginAttempts: attempts }); - } + await chrome.runtime.sendMessage({ action: "resetDomainAttempts", envId, domain }).catch(() => {}); } async function loadAllConfigs() { - const data = await safeStorageGet("session", "environments"); - const environments = data.environments || []; - const all = []; - environments.forEach((env) => { - (env.configs || []).forEach((cfg) => { - all.push({ ...cfg, envId: env.id, envName: env.name }); - }); - }); - return all; + const resp = await chrome.runtime.sendMessage({ action: "loadAllConfigs" }).catch(() => null); + return resp?.configs || []; } async function autoFillOnLoad() { let allConfigs = await loadAllConfigs(); if (allConfigs.length === 0) { // session 可能为空(明文模式 SW 重启后未初始化),触发 background 加载后重试 + let resp = null; try { - await chrome.runtime.sendMessage({ action: "getVaultStatus" }); + resp = await chrome.runtime.sendMessage({ action: "getVaultStatus" }); allConfigs = await loadAllConfigs(); - } catch {} + } catch (e) { + showDiag("初始化失败: " + (e.message || e)); + return; + } + if (allConfigs.length === 0) { + showDiag("无配置 | local: envs=" + (resp?.localEnvs) + " cfgs=" + (resp?.localCfgs) + " | session: envs=" + (resp?.sessEnvs) + " cfgs=" + (resp?.sessCfgs)); + return; + } } - if (allConfigs.length === 0) return; // 每个配置有独立开关 enabled const enabledConfigs = allConfigs.filter((c) => c.enabled !== false); - if (enabledConfigs.length === 0) return; + if (enabledConfigs.length === 0) { + showDiag("所有配置已禁用"); + return; + } const matched = enabledConfigs.filter((c) => isDomainMatch(window.location.href, c.domain)); - if (matched.length === 0) return; + if (matched.length === 0) { + showDiag("未匹配: " + window.location.href + " | 配置: " + enabledConfigs.map((c) => c.domain).join(", ")); + return; + } if (matched.length === 1) { await fillSingleConfig(matched[0]); @@ -484,7 +485,9 @@ async function fillSingleConfig(config) { const tryFill = () => { const elapsed = Date.now() - startTime; if (elapsed > SPA_FILL_TIMEOUT_MS) { - console.warn("[AutoLogin]", t("logSpaTimeout", String(SPA_FILL_TIMEOUT_MS / 1000))); + const inputs = deepQuerySelectorAll("input"); + const pwd = deepQuerySelectorAll("input[type='password']"); + showDiag("填充超时: input=" + inputs.length + " pwd=" + pwd.length + " form=" + document.querySelectorAll("form").length + " | " + inputs.slice(0, 6).map((i) => "type=" + (i.type || "?") + "/name=" + (i.name || i.id || "?")).join(", ")); return; } const filled = fillForm(config, canSubmit);