no message
This commit is contained in:
@@ -34,6 +34,7 @@ async function migrateLegacyVault() {
|
||||
|
||||
// 无 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) {
|
||||
@@ -54,6 +55,9 @@ async function ensurePlainEnvironments() {
|
||||
}
|
||||
}
|
||||
|
||||
// SW 启动即初始化明文环境到 session,供 content script 自动登录读取
|
||||
ensurePlainEnvironments().catch((err) => console.warn("[AutoLogin] 启动初始化失败:", err));
|
||||
|
||||
|
||||
function resetAutoLockTimer() {
|
||||
if (autoLockTimer) clearTimeout(autoLockTimer);
|
||||
|
||||
+64
-14
@@ -71,11 +71,28 @@ function setNativeValue(el, value) {
|
||||
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) {
|
||||
if (!value) return null;
|
||||
const trimmed = value.trim();
|
||||
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 el = doc.body.firstElementChild;
|
||||
@@ -94,10 +111,10 @@ function resolveElement(value, multiple) {
|
||||
candidates.push(tag);
|
||||
for (const sel of candidates) {
|
||||
if (multiple) {
|
||||
const els = Array.from(document.querySelectorAll(sel));
|
||||
const els = deepQuerySelectorAll(sel);
|
||||
if (els.length) return els;
|
||||
} else {
|
||||
const found = document.querySelector(sel);
|
||||
const found = deepQuerySelector(sel);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
@@ -123,7 +140,7 @@ function findUsernameField(config) {
|
||||
];
|
||||
|
||||
for (const sel of selectors) {
|
||||
const inputs = searchScope.querySelectorAll(sel);
|
||||
const inputs = deepQuerySelectorAll(sel, searchScope);
|
||||
for (const input of inputs) {
|
||||
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
||||
const name = (input.name || "").toLowerCase();
|
||||
@@ -148,8 +165,9 @@ function findUsernameField(config) {
|
||||
}
|
||||
}
|
||||
|
||||
const allInputs = searchScope.querySelectorAll(
|
||||
"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'])"
|
||||
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'])",
|
||||
searchScope
|
||||
);
|
||||
for (const input of allInputs) {
|
||||
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
||||
@@ -166,14 +184,26 @@ function findPasswordField(config) {
|
||||
if (el) return el;
|
||||
}
|
||||
|
||||
const passwordInputs = document.querySelectorAll("input[type='password']");
|
||||
const passwordInputs = deepQuerySelectorAll("input[type='password']");
|
||||
for (const input of passwordInputs) {
|
||||
if (input.offsetParent !== null || input.offsetWidth > 0) {
|
||||
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) {
|
||||
@@ -205,7 +235,7 @@ function findSubmitButton(config, passwordField) {
|
||||
];
|
||||
|
||||
for (const sel of submitSelectors) {
|
||||
const btns = searchScope.querySelectorAll(sel);
|
||||
const btns = deepQuerySelectorAll(sel, searchScope);
|
||||
for (const btn of btns) {
|
||||
if (btn.offsetParent !== null || btn.offsetWidth > 0) {
|
||||
const text = (btn.textContent || btn.value || "").toLowerCase().trim();
|
||||
@@ -222,13 +252,13 @@ function findSubmitButton(config, passwordField) {
|
||||
}
|
||||
|
||||
for (const sel of submitSelectors) {
|
||||
const btn = searchScope.querySelector(sel);
|
||||
const btn = deepQuerySelector(sel, searchScope);
|
||||
if (btn && (btn.offsetParent !== null || btn.offsetWidth > 0)) {
|
||||
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) {
|
||||
if (btn.offsetParent !== null || btn.offsetWidth > 0) {
|
||||
const text = (btn.textContent || btn.value || "").toLowerCase().trim();
|
||||
@@ -390,7 +420,14 @@ async function loadAllConfigs() {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 每个配置有独立开关 enabled
|
||||
@@ -556,10 +593,23 @@ function showEnvPicker(configs) {
|
||||
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
if (message.action === "manualFill" && message.config) {
|
||||
// 手动触发填充,重置失败计数
|
||||
resetDomainAttempts(message.config.envId, message.config.domain);
|
||||
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)) {
|
||||
showEnvPicker(message.configs);
|
||||
sendResponse({ success: true });
|
||||
|
||||
@@ -1006,6 +1006,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
if (resp && resp.success) {
|
||||
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 {
|
||||
showToast(t("toastFilledNoForm"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user