Skip to content

Latest commit

 

History

History
128 lines (99 loc) · 4.42 KB

File metadata and controls

128 lines (99 loc) · 4.42 KB

OTP 自动填充功能实现分析报告

1. 概述

本报告分析了在浏览器插件中实现一次性密码(OTP)自动填充功能所需的需求和代码变更。此功能依赖于 KeePassRPC 后端的更新,该更新已将 OTP 值暴露给客户端。

2. 后端集成

KeePassRPC 插件已进行修改,在 Entry 数据模型中包含了一个公开的 Otp 字符串字段。用于获取条目的 JSON-RPC 响应现在将包含此字段。

3. 实现计划

3.1. 更新数据传输对象 (DTOs)

我们需要更新 TypeScript 接口,以便将 JSON-RPC 响应映射到前端时能够识别新的 otp 字段。

  • 文件: src/common/model/KPRPCDTOs.ts
  • 操作: 在 EntryDto 类中添加 otp 属性。
export class EntryDto {
    // ... 现有字段
    title: string;
    formFieldList: FieldDto[];
    otp?: string; // 新增此字段
}

3.2. 更新条目 (Entry) 模型

内部的 Entry 模型需要接收此新数据并将其转换为 Field 对象,以便自动填充逻辑可以使用它。

  • 文件: src/common/model/Entry.ts
  • 操作: 更新 fromKPRPCEntryDTO 方法以创建 OTP 字段。
// 在 Entry.fromKPRPCEntryDTO 方法中:

// ... 现有代码 ...
const firstPasswordIndex = unsortedFields.findIndex(f => f.type === "password");

// 添加此代码块
if (entryDto.otp) {
    const otpField = new Field({
        name: "OTP", // 显示名称
        type: "otp",
        value: entryDto.otp,
        locators: [
            new Locator({
                name: "otp",
                id: "otp",
                type: "otp" // 这将有助于匹配逻辑
            })
        ]
    });
    // 添加到 sortedFields
    sortedFields.push(otpField);
}
// ... 现有代码 ...

3.3. 表单填充逻辑 (核心)

目前的表单填充逻辑依赖于严格的类型匹配。我们需要针对 OTP 字段放宽这一限制,并增加自动刷新功能。

  • 文件: src/page/formFilling.ts
  • 操作 1: 更新 calculateFieldMatchScore 以支持更广泛的 OTP 匹配(包括 password 类型和标签上下文)。
// 定义关键词
const OTP_KEYWORDS = [
    "otp", "totp", "2fa", "token", "code", "verification", 
    "验证码", "动态密码", "一次性密码", "安全码", "动态安全码", "passwd1"
];
const OTP_LABEL_KEYWORDS = [
    "mfa", "device", "serial", "google authenticator", "authenticator", 
    "验证", "虚拟", "设备"
];

// 在 calculateFieldMatchScore 方法中:

// 1. 类型匹配放宽:允许 OTP 匹配 text, password, tel, number
if (formField.type !== dataField.type) {
    const isOtpMatchingText = dataField.type === "otp" && 
                              (formField.type === "text" || formField.type === "password" || 
                               formField.type === "tel" || formField.type === "number");
    if (!isOtpMatchingText) return 0;
}

// 2. 评分逻辑增强
if (dataField.type === "otp") {
    let otpScore = 0;
    // ... 获取 name, id, labels, placeholder ...

    // 强信号: autocomplete="one-time-code" (+100)
    
    // 强信号: 标签或占位符包含上下文关键词 (MFA, Device 等) (+80)
    
    // 启发式: Name/ID 包含 OTP 关键词 (+50)
    
    // 惩罚: 看起来像用户名或搜索字段 (-100)
    
    score += otpScore;
} else {
    // 防御性:普通字段如果匹配到了 OTP 关键词,给予惩罚 (-100),防止误填
}
  • 操作 2: 实现 OTP 自动刷新机制。
// 在 FormFilling 类中:

// 调度刷新
private scheduleOtpRefresh() {
    // 计算距离下一个 30秒 周期的时间 + 2秒缓冲
    // setTimeout 触发后调用 findMatchesInThisFrame 重新获取数据
}

// 在 fillMatchedFields 中检测到 OTP 填充后调用 scheduleOtpRefresh

4. UI 考量 (可选)

虽然自动填充是主要目标,但在弹出窗口或上下文菜单中显示 OTP 可能也是需要的。

  • 由于我们将 OTP 作为 Field 添加到了 Entry 对象中,只要 UI 遍历并显示 entry.fields,且能正确处理 otp 字段类型(通常默认为文本显示),它就应该自动出现。
  • 文件: src/common/model/Field.ts - 确保 getDisplayValue 能处理 otp 类型。

5. 下一步

  1. 修改 src/common/model/KPRPCDTOs.ts
  2. 修改 src/common/model/Entry.ts
  3. 修改 src/page/formFilling.ts
  4. 构建并使用修改后的 KeePassRPC 插件进行测试。