Files
auto-login/dist/background.js
T
陈银军 9ccc9253d3 清理冗余代码:删除未使用变量、types.ts 改为 .d.ts、测试路径改引 dist/
- 删除未使用的 getActiveEnv 解构、sender 参数改为 _sender
- types.ts 重命名为 types.d.ts,消除无用的 dist/types.js 产物
- 测试文件引用路径从根目录改为 dist/
2026-09-17 01:44:53 +08:00

245 lines
10 KiB
JavaScript

"use strict";
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));
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));
autoRestoreUnlock().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();
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
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();
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;
}
if (!masterKey)
await autoRestoreUnlock();
sendResponse({ hasVault, unlocked: !!masterKey, pendingImport: false });
break;
}
case "loadAllConfigs": {
if (!(await CryptoStore.hasVault()))
await ensurePlainEnvironments();
const data = await chrome.storage.session.get("environments");
const environments = data.environments || [];
const all = [];
environments.forEach((env) => {
(env.configs || []).forEach((cfg) => all.push({ ...cfg, envId: env.id, envName: env.name }));
});
sendResponse({ configs: all });
break;
}
case "getDomainAttempts": {
const key = `${message.envId}::${message.domain}`;
const data = await chrome.storage.local.get("loginAttempts");
const attempts = data.loginAttempts || {};
sendResponse({ attempts: attempts[key] || { count: 0, lastAttempt: 0 } });
break;
}
case "incrementDomainAttempts": {
const key = `${message.envId}::${message.domain}`;
const data = await chrome.storage.local.get("loginAttempts");
const attempts = data.loginAttempts || {};
const cur = attempts[key] || { count: 0, lastAttempt: 0 };
cur.count += 1;
cur.lastAttempt = Date.now();
attempts[key] = cur;
await chrome.storage.local.set({ loginAttempts: attempts });
sendResponse({ attempts: cur });
break;
}
case "resetDomainAttempts": {
const key = `${message.envId}::${message.domain}`;
const data = await chrome.storage.local.get("loginAttempts");
const attempts = data.loginAttempts || {};
if (attempts[key]) {
delete attempts[key];
await chrome.storage.local.set({ loginAttempts: attempts });
}
sendResponse({ success: true });
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.session.set({ __autoPwd: message.password });
await chrome.storage.local.remove("environments"); // 已加密,明文不再需要
resetAutoLockTimer();
sendResponse({ success: true });
break;
}
case "unlock": {
try {
const { key } = await CryptoStore.unlock(message.password);
masterKey = key;
await chrome.storage.session.set({ __autoPwd: message.password });
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; // 异步响应
});