feat: 按域名授权、iframe 多帧填充、自动提交限流修正,并补齐工程规范与文档

安全与权限:
- 站点访问权限改为 optional_host_permissions,保存配置时逐域名授权;移除 host_permissions 与 tabs,安装提示不再出现全站数据访问与浏览记录
- 主口令不再写入 storage.session,改用 IndexedDB 中不可导出的 CryptoKey 句柄恢复解锁,锁定即丢弃
- content script 注入范围只注册已授权域名,并随权限变化即时收敛

自动登录:
- 支持 iframe 内的登录表单:脚本注入所有帧,逐帧按自身地址匹配配置
- 手动填充改为逐帧探测,定向发送到真正含密码框的帧
- 限流修正:只在真正触发提交后计数;判定登录成功后立即清零;达到上限时页面给出可见提示;重置判断只看启用中的配置
- SPA 重试改为 DOM 变更门控 + 退避,并单独监听已发现的 Shadow Root

工程化与文档:
- 引入 ESLint(扁平配置)与 Prettier,CI 增加 lint 与 format:check
- 信息类日志改为 debugLog(默认静默,chrome.storage.local.debugLog 开关)
- 测试 123 → 128 用例(新增权限、iframe、限流相关用例)
- README / PRIVACY / CHANGELOG 同步
This commit is contained in:
陈银军
2026-09-18 00:05:20 +08:00
parent 8883a5c506
commit 1b0c3c012c
48 changed files with 3364 additions and 680 deletions
+22 -7
View File
@@ -3,7 +3,7 @@
* 添加按钮提交、"填入当前域名"按钮。
*/
import { t } from "../i18n.js";
import { fetchTitleByDomain } from "../ui-utils.js";
import { resolveAlias } from "../ui-utils.js";
import type { DomainConfig } from "../types.js";
import { $ } from "./dom";
import type { PopupCtx } from "./context";
@@ -24,9 +24,16 @@ const fillDomainBtn = $("fillDomain");
const DRAFT_KEY = "formDraft";
const draftFields = [
domainInput, aliasInput, usernameInput, passwordInput, autoSubmitSelect,
usernameSelectorInput, passwordSelectorInput, submitSelectorInput,
enabledCheckbox, delayMsInput,
domainInput,
aliasInput,
usernameInput,
passwordInput,
autoSubmitSelect,
usernameSelectorInput,
passwordSelectorInput,
submitSelectorInput,
enabledCheckbox,
delayMsInput,
];
export function initConfigForm(ctx: PopupCtx) {
@@ -98,10 +105,13 @@ export function initConfigForm(ctx: PopupCtx) {
return;
}
// 申请站点访问权限必须紧跟用户手势,因此放在其它 await 之前
const authorized = await Perms.requestForDomain(domain);
const config: DomainConfig = {
id: EnvStore.genCfgId(),
domain,
alias: aliasInput.value.trim() || await fetchTitleByDomain(domain) || null,
alias: aliasInput.value.trim() || (await resolveAlias(domain)) || null,
username,
password,
autoSubmit: autoSubmitSelect.value === "true",
@@ -115,7 +125,7 @@ export function initConfigForm(ctx: PopupCtx) {
const configs = await EnvStore.loadConfigs();
configs.push(config);
ctx.showToast(t("toastAdded"));
ctx.showToast(authorized ? t("toastAdded") : t("toastUnauthorized"));
await EnvStore.saveConfigs(configs);
resetForm();
@@ -127,10 +137,15 @@ export function initConfigForm(ctx: PopupCtx) {
// 填入当前标签页域名
fillDomainBtn.addEventListener("click", async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab || !tab.url) {
if (!tab) {
ctx.showToast(t("toastNoTab"));
return;
}
if (!tab.url) {
// 未授权时读不到地址:提示用户点扩展图标重新授予 activeTab
ctx.showToast(t("toastNoTabUrl"));
return;
}
try {
const u = new URL(tab.url);
const host = u.host;