no message
This commit is contained in:
+30
-3
@@ -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) {
|
||||
|
||||
+38
-35
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user