no message
This commit is contained in:
@@ -34,6 +34,7 @@ async function migrateLegacyVault() {
|
|||||||
|
|
||||||
// 无 vault 明文模式:确保 session 有 environments(从 local 加载或创建预设)
|
// 无 vault 明文模式:确保 session 有 environments(从 local 加载或创建预设)
|
||||||
async function ensurePlainEnvironments() {
|
async function ensurePlainEnvironments() {
|
||||||
|
if (await CryptoStore.hasVault()) return; // 加密模式不处理
|
||||||
const data = await chrome.storage.local.get("environments");
|
const data = await chrome.storage.local.get("environments");
|
||||||
let envs = data.environments;
|
let envs = data.environments;
|
||||||
if (!Array.isArray(envs) || envs.length === 0) {
|
if (!Array.isArray(envs) || envs.length === 0) {
|
||||||
@@ -54,6 +55,9 @@ async function ensurePlainEnvironments() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SW 启动即初始化明文环境到 session,供 content script 自动登录读取
|
||||||
|
ensurePlainEnvironments().catch((err) => console.warn("[AutoLogin] 启动初始化失败:", err));
|
||||||
|
|
||||||
|
|
||||||
function resetAutoLockTimer() {
|
function resetAutoLockTimer() {
|
||||||
if (autoLockTimer) clearTimeout(autoLockTimer);
|
if (autoLockTimer) clearTimeout(autoLockTimer);
|
||||||
|
|||||||
+64
-14
@@ -71,11 +71,28 @@ function setNativeValue(el, value) {
|
|||||||
el.dispatchEvent(new Event("change", { bubbles: true }));
|
el.dispatchEvent(new Event("change", { bubbles: true }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deepQuerySelectorAll(selector, root) {
|
||||||
|
const result = [];
|
||||||
|
const stack = [root || document];
|
||||||
|
while (stack.length) {
|
||||||
|
const r = stack.pop();
|
||||||
|
result.push(...r.querySelectorAll(selector));
|
||||||
|
for (const el of r.querySelectorAll("*")) {
|
||||||
|
if (el.shadowRoot) stack.push(el.shadowRoot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepQuerySelector(selector, root) {
|
||||||
|
return deepQuerySelectorAll(selector, root)[0] || null;
|
||||||
|
}
|
||||||
|
|
||||||
function resolveElement(value, multiple) {
|
function resolveElement(value, multiple) {
|
||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
const trimmed = value.trim();
|
const trimmed = value.trim();
|
||||||
if (!trimmed.startsWith("<")) {
|
if (!trimmed.startsWith("<")) {
|
||||||
return multiple ? Array.from(document.querySelectorAll(trimmed)) : document.querySelector(trimmed);
|
return multiple ? deepQuerySelectorAll(trimmed) : deepQuerySelector(trimmed);
|
||||||
}
|
}
|
||||||
const doc = new DOMParser().parseFromString(trimmed, "text/html");
|
const doc = new DOMParser().parseFromString(trimmed, "text/html");
|
||||||
const el = doc.body.firstElementChild;
|
const el = doc.body.firstElementChild;
|
||||||
@@ -94,10 +111,10 @@ function resolveElement(value, multiple) {
|
|||||||
candidates.push(tag);
|
candidates.push(tag);
|
||||||
for (const sel of candidates) {
|
for (const sel of candidates) {
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
const els = Array.from(document.querySelectorAll(sel));
|
const els = deepQuerySelectorAll(sel);
|
||||||
if (els.length) return els;
|
if (els.length) return els;
|
||||||
} else {
|
} else {
|
||||||
const found = document.querySelector(sel);
|
const found = deepQuerySelector(sel);
|
||||||
if (found) return found;
|
if (found) return found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,7 +140,7 @@ function findUsernameField(config) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for (const sel of selectors) {
|
for (const sel of selectors) {
|
||||||
const inputs = searchScope.querySelectorAll(sel);
|
const inputs = deepQuerySelectorAll(sel, searchScope);
|
||||||
for (const input of inputs) {
|
for (const input of inputs) {
|
||||||
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
||||||
const name = (input.name || "").toLowerCase();
|
const name = (input.name || "").toLowerCase();
|
||||||
@@ -148,8 +165,9 @@ function findUsernameField(config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const allInputs = searchScope.querySelectorAll(
|
const allInputs = deepQuerySelectorAll(
|
||||||
"input[type='text'], input[type='email'], input:not([type='password']):not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio'])"
|
"input[type='text'], input[type='email'], input:not([type='password']):not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio'])",
|
||||||
|
searchScope
|
||||||
);
|
);
|
||||||
for (const input of allInputs) {
|
for (const input of allInputs) {
|
||||||
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
||||||
@@ -166,14 +184,26 @@ function findPasswordField(config) {
|
|||||||
if (el) return el;
|
if (el) return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
const passwordInputs = document.querySelectorAll("input[type='password']");
|
const passwordInputs = deepQuerySelectorAll("input[type='password']");
|
||||||
for (const input of passwordInputs) {
|
for (const input of passwordInputs) {
|
||||||
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (passwordInputs.length > 0) return passwordInputs[0];
|
||||||
|
|
||||||
return passwordInputs.length > 0 ? passwordInputs[0] : null;
|
const allInputs = deepQuerySelectorAll("input");
|
||||||
|
for (const input of allInputs) {
|
||||||
|
if (input.type === "password") return input;
|
||||||
|
const sig = (
|
||||||
|
(input.name || "") + " " + (input.id || "") + " " +
|
||||||
|
(input.placeholder || "") + " " + (input.getAttribute("autocomplete") || "")
|
||||||
|
).toLowerCase();
|
||||||
|
if (sig.includes("password") || sig.includes("passwd") || sig.includes("pwd")) {
|
||||||
|
if (input.offsetParent !== null || input.offsetWidth > 0) return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findSubmitButton(config, passwordField) {
|
function findSubmitButton(config, passwordField) {
|
||||||
@@ -205,7 +235,7 @@ function findSubmitButton(config, passwordField) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for (const sel of submitSelectors) {
|
for (const sel of submitSelectors) {
|
||||||
const btns = searchScope.querySelectorAll(sel);
|
const btns = deepQuerySelectorAll(sel, searchScope);
|
||||||
for (const btn of btns) {
|
for (const btn of btns) {
|
||||||
if (btn.offsetParent !== null || btn.offsetWidth > 0) {
|
if (btn.offsetParent !== null || btn.offsetWidth > 0) {
|
||||||
const text = (btn.textContent || btn.value || "").toLowerCase().trim();
|
const text = (btn.textContent || btn.value || "").toLowerCase().trim();
|
||||||
@@ -222,13 +252,13 @@ function findSubmitButton(config, passwordField) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const sel of submitSelectors) {
|
for (const sel of submitSelectors) {
|
||||||
const btn = searchScope.querySelector(sel);
|
const btn = deepQuerySelector(sel, searchScope);
|
||||||
if (btn && (btn.offsetParent !== null || btn.offsetWidth > 0)) {
|
if (btn && (btn.offsetParent !== null || btn.offsetWidth > 0)) {
|
||||||
return btn;
|
return btn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const allButtons = searchScope.querySelectorAll("button, input[type='button'], a[role='button']");
|
const allButtons = deepQuerySelectorAll("button, input[type='button'], a[role='button']", searchScope);
|
||||||
for (const btn of allButtons) {
|
for (const btn of allButtons) {
|
||||||
if (btn.offsetParent !== null || btn.offsetWidth > 0) {
|
if (btn.offsetParent !== null || btn.offsetWidth > 0) {
|
||||||
const text = (btn.textContent || btn.value || "").toLowerCase().trim();
|
const text = (btn.textContent || btn.value || "").toLowerCase().trim();
|
||||||
@@ -390,7 +420,14 @@ async function loadAllConfigs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function autoFillOnLoad() {
|
async function autoFillOnLoad() {
|
||||||
const allConfigs = await loadAllConfigs();
|
let allConfigs = await loadAllConfigs();
|
||||||
|
if (allConfigs.length === 0) {
|
||||||
|
// session 可能为空(明文模式 SW 重启后未初始化),触发 background 加载后重试
|
||||||
|
try {
|
||||||
|
await chrome.runtime.sendMessage({ action: "getVaultStatus" });
|
||||||
|
allConfigs = await loadAllConfigs();
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
if (allConfigs.length === 0) return;
|
if (allConfigs.length === 0) return;
|
||||||
|
|
||||||
// 每个配置有独立开关 enabled
|
// 每个配置有独立开关 enabled
|
||||||
@@ -556,10 +593,23 @@ function showEnvPicker(configs) {
|
|||||||
|
|
||||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
if (message.action === "manualFill" && message.config) {
|
if (message.action === "manualFill" && message.config) {
|
||||||
// 手动触发填充,重置失败计数
|
|
||||||
resetDomainAttempts(message.config.envId, message.config.domain);
|
resetDomainAttempts(message.config.envId, message.config.domain);
|
||||||
const filled = fillForm(message.config, true);
|
const filled = fillForm(message.config, true);
|
||||||
sendResponse({ success: filled });
|
if (filled) {
|
||||||
|
sendResponse({ success: true });
|
||||||
|
} else {
|
||||||
|
const inputs = deepQuerySelectorAll("input");
|
||||||
|
const pwdInputs = deepQuerySelectorAll("input[type='password']");
|
||||||
|
sendResponse({
|
||||||
|
success: false,
|
||||||
|
diag: {
|
||||||
|
total: inputs.length,
|
||||||
|
pwd: pwdInputs.length,
|
||||||
|
forms: document.querySelectorAll("form").length,
|
||||||
|
sample: inputs.slice(0, 10).map((i) => `type=${i.type || "?"}|name=${(i.name || i.id || i.placeholder || "?").slice(0, 20)}`),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
} else if (message.action === "manualFillMulti" && Array.isArray(message.configs)) {
|
} else if (message.action === "manualFillMulti" && Array.isArray(message.configs)) {
|
||||||
showEnvPicker(message.configs);
|
showEnvPicker(message.configs);
|
||||||
sendResponse({ success: true });
|
sendResponse({ success: true });
|
||||||
|
|||||||
@@ -1006,6 +1006,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
if (resp && resp.success) {
|
if (resp && resp.success) {
|
||||||
showToast(t("toastFilled"));
|
showToast(t("toastFilled"));
|
||||||
|
} else if (resp && resp.diag) {
|
||||||
|
const d = resp.diag;
|
||||||
|
showToast(`input=${d.total} pwd=${d.pwd} form=${d.forms} | ${d.sample.join(", ")}`);
|
||||||
} else {
|
} else {
|
||||||
showToast(t("toastFilledNoForm"));
|
showToast(t("toastFilledNoForm"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user