# 软件认证器

> 配置软件 WebAuthn 凭据、处理注册保存回调，并管理本地或外部签名计数器。

Source: https://console.getchrovia.com/zh/docs/sdk-software-authenticator

**能力：**`softwareAuthenticator`。**EP：**`internal.software_authenticator`。网站使用标准 `navigator.credentials.create()` 和 `get()`，没有 `chrovia.softwareAuthenticator` JS 域。注册保存回复还需要 `messaging` 和负责处理的 Provision 插件。

## 配置认证器

```json
{
  "internal": {
    "software_authenticator": {
      "config": {
        "disguise_as": "windows_hello",
        "display_name": "SDK Passkey Vault",
        "counter_source": "local"
      }
    }
  }
}
```

| 字段 | 可选值与默认值 |
| --- | --- |
| `config.disguise_as` | `windows_hello`、`icloud_keychain`、`gpm_phone`；默认 `gpm_phone` |
| `config.display_name` | 非空界面名称，默认 `Passkey Vault` |
| `config.counter_source` | `external` 为会递增的预设向插件申请计数器，其他值使用本地 |
| `credentials` | 导入此前保存凭据时使用的序列化记录数组 |

选择新注册的通行密钥向网站呈现的方式。这些预设不会将通行密钥保存到真实 Windows Hello、iCloud 或手机，也不提供硬件凭据。更改预设影响后续注册，不改变已有通行密钥。

测试时，安装配置和保存处理器后完全重启，打开网站账号安全设置并选择添加通行密钥。出现选项时选择配置的凭据库名称，然后完成网站确认。退出网站账号，再选择通行密钥登录，并在提示时选择已保存账号。测试期间应保留其他登录方式。

## 注册需要保存回复

每次 Provision Service Worker 启动时注册。以下最小例子批准**本地测试注册**，内核收到批准后才保存记录：

```js
const messaging = globalThis.chrovia?.messaging;
if (messaging) {
  messaging.on('chrovia.software_authenticator.credential.save', data => {
    const channel = data?.callback_channel;
    if (data?.action !== 'save_credential'
        || typeof channel !== 'string'
        || !channel.startsWith('chrovia.software_authenticator.credential.save.reply.')) {
      return;
    }
    messaging.emit(channel, { success: true });
  });
}
```

请求包含完整凭据记录、`action: "save_credential"` 和 `callback_channel`。回复 `{success: true}` 接受，或 `{success: false}` 拒绝。失败或 30 秒未回复会拒绝注册。监听器直接 return 一个值不等于回复。

接入受控凭据库时，应先验证并持久化记录，再回复成功。载荷包含敏感登录数据，不要记录日志。不要安装两个同时响应注册通道的插件。

使用 HTTPS/localhost 依赖方测试站点，或 Chrovia Studio 软件认证器演示进行注册和登录。仍需遵守普通 WebAuthn 的 origin、RP、challenge 和服务端验证要求。只有浏览器端凭据不等于服务端已注册账号，也不保证每个网站或 headless 流程都能无人值守成功。

## 备份、恢复与移除通行密钥

将每条凭据视为不可拆解的完整记录：保留所有字段和值，不要解码或重新构造内容。使用 `rp_id` 识别网站、`user_id` 识别账号、`credential_id` 识别通行密钥，可选的 `user_name` / `user_display_name` 用于展示。标识值应原样保留。

保存请求的顶层包含这些记录字段，以及 `action` 和 `callback_channel`。存入凭据库时去掉这两个消息路由字段。同一 `rp_id` 和 `user_id` 注册新通行密钥，会替换此前的本地通行密钥，因此应替换凭据库中该账号的条目，不要直接追加。网站确认注册成功后，再依赖新通行密钥登录。

恢复或移除本地通行密钥：

1. 完全退出实例，备份当前 Extended Preferences 文件。保留 `internal.software_authenticator.credentials` 中近期的完整凭据列表，其中可能包含注册后产生的更新。通过 `chrovia.prefs` 读取还需要 `extendedPrefs`。
2. 用已保存记录准备完整的目标 `credentials` 数组。移除某个通行密钥时省略对应记录；全部移除时使用空数组。保留文档的其他内容和认证器配置。
3. 未签名偏好可以在实例关闭时替换文件中的 `internal.software_authenticator.credentials`。已签名偏好需要获取包含目标列表的新签名文件。
4. 重启实例，在原网站测试登录。修改列表不会刷新已运行的实例。

格式错误或不完整的记录可能被跳过，不要编造占位值。恢复浏览器记录不会在网站注册账号；本地移除也不会撤销网站上的注册，或删除其他凭据库中的副本。应在网站账号安全设置中另行管理。备份和保存载荷应保密，不要交给网站脚本。

## 外部计数器

使用 `counter_source: "external"` 时，内核可发送 `chrovia.software_authenticator.counter.claim`，包含 `action: "claim_counter"`、`rp_id`、base64 `credential_id` 和 `callback_channel`。在该通道回复 `{success: true, counter: "42"}`，计数器应是由凭据库原子分配的非负 uint32 十进制字符串。

同一凭据跨实例必须协调分配，不要复用示例常量。失败、无效或缺失的回复会在最多 30 秒后回退本地计数行为，不会自动拒绝登录。

外部计数请求适用于使用 `windows_hello` 或 `icloud_keychain` 注册的通行密钥。默认 `gpm_phone` 预设报告零，不请求外部计数器。需要分配计数器时，应在注册前选择会递增的预设。之后修改 `disguise_as` 不会改变已有通行密钥。

## 使用已签名配置

开启 `signedExtendedPrefs` 后，注册或使用通行密钥可能使当前 EP 文件在下次启动时不可用。重启前应获取包含最新凭据列表的[已签名 EP](https://console.getchrovia.com/zh/docs/sdk-signed-extended-prefs)。回复保存成功不会更新已签名文件。

未签名本地测试应使用不含 `signedExtendedPrefs` 的已签发 License。

TOTP 秘密和[已保存密码](https://console.getchrovia.com/zh/docs/sdk-passwords)使用不同数据和协议，不要作为软件 WebAuthn 凭据存储。
