96 lines
7.8 KiB
Markdown
96 lines
7.8 KiB
Markdown
# 第三方人机验证优化改造计划
|
||
|
||
约束:不写双路/兼容迁移代码;顺手清理死代码;不做真实视觉效果验收(用语法检查、契约测试、构建产物校验代替)。
|
||
已确认决策:范围全做(P0+P1+P2);下载场景 pass 放行 10 分钟;凭据不齐时仅加后台警告、前台保持放行。
|
||
|
||
## 改动文件总览
|
||
|
||
| 文件 | 动作 |
|
||
|---|---|
|
||
| `inc/modules/captcha.php` | 重写校验层 + 瘦身渲染 + 后台警告 + 静态缓存 |
|
||
| `assets/js/captcha-front.js` | 新建(从内联脚本迁移,~340 行) |
|
||
| `assets/css/shared/captcha.css` | 保留不动(改为进 bundle) |
|
||
| `tools/build-public-assets.mjs` | publicScripts 加 captcha-front.js;public.css 加 captcha.css |
|
||
| `src/Admin/Schema/SchemaPermissions.php` | 删除 'mode' 死字段(L32-34) |
|
||
| `assets/admin/src/schema/sections/permissions/index.js` | 删除 'mode' 死字段(L18 defaults、L50-56) |
|
||
| `src/Admin/SchemaProvider.php` | L403 白名单删 'mode';保存后 flush 配置静态缓存 |
|
||
| `tests/widget-system/captcha-cloud-contract.test.cjs` | 新建契约测试 |
|
||
|
||
不动的文件及原因:`aksrt-header-userbox.php`(toast-contract 测试锁定 signin 接线)、`data-aksrt-download-captcha` 挂载点(`templates/parts/resource-download-box.php:467`、`inc/helpers/aksrt-pay.php:1586`)、所有业务 JS(auth/signin/comments/cms-download/user-center/front-submit 只消费 `AKSRTCaptchaState.scenes[scene]` 与 mount 内 token input,接口不变即零改动)。
|
||
|
||
## 1. inc/modules/captcha.php — 校验层
|
||
|
||
**P0-1 腾讯云改走 WP HTTP API**:`aksrt_verify_tencent()` 删除 curl 块(L374-390,含 `CURLOPT_SSL_VERIFYPEER => false`),改用 `wp_remote_post('https://captcha.tencentcloudapi.com/', ['timeout'=>5, 'headers'=>aksrt_tencent_tc3_sign(...)生成的一维数组, 'body'=>$payload])`,与另外三家一致。签名函数不动。
|
||
|
||
**P1-5 错误信息收敛**:四家服务商的传输层错误(wp_remote_post 返回 WP_Error、响应不可解析)统一 `error_log('[AKSRT Captcha] {provider}: ' . 详情)` 后返回通用文案 `__('人机验证服务暂不可用,请稍后重试', 'aksrt')`;保留对用户有行动意义的映射文案(腾讯 CaptchaCode 表、阿里 F0xx 表)。腾讯 API Error 分支(签名错误等)也走 log+通用文案。
|
||
|
||
**P1-4**:阿里云 `SignatureNonce` 由 `uniqid('', true)` 改 `wp_generate_uuid4()`。
|
||
|
||
**P1-8**:四家 `'timeout'` 统一 5 秒(现 10 秒)。
|
||
|
||
**P1-6 Turnstile 绑定场景**:`aksrt_verify_captcha($post_data, $scene = '')` 增加第二参数(唯一调用方是 `aksrt_require_captcha`,无散落调用点);Cloudflare 成功响应校验:`action !== 'aksrt-verify'` 或 `cdata !== $scene`(存在才比对,lenient)→ 失败。客户端配套见 §2。
|
||
|
||
**P0-2 下载 pass 放行(10 分钟)**:`aksrt_require_captcha()` 内,scene 命中放行名单时先查 transient、验证通过后写 transient:
|
||
- `aksrt_captcha_pass_ttl($scene)`:仅 `download` 返回 `10 * MINUTE_IN_SECONDS`,其余返回 0(单一代码路径,无散落分支)
|
||
- key = `'aksrt_captcha_pass_' . md5($scene . '|' . get_current_user_id() . '|' . aksrt_get_client_ip() . '|' . md5(UA))`,仿 `aksrt_auth_rate_` 既有模式
|
||
|
||
## 2. assets/js/captcha-front.js — 新建(P2-9 + P1-7 客户端)
|
||
|
||
把 `aksrt_render_captcha()` 内联 `<script>`(L632-969)整体迁移为静态文件,逻辑不改名不重写:`loadScriptOnce`、四家 `load*`、`AKSRTCaptchaState.scenes[scene].verify/reset` 注册、`setField/resetVerificationState/syncDownloadSiblings` 等原样搬移。仅两处行为修正:
|
||
- 极验 `onClose` 空回调改为 `cancelPending('已取消验证')`(P1-7,与腾讯/CF 取消体验对齐)
|
||
- Turnstile render 配置加 `cdata: C.scene`(P1-6 客户端配套)
|
||
|
||
激活模型:扫描 `document.querySelectorAll('[data-aksrt-captcha-config]')`,`JSON.parse(el.getAttribute(...))` 逐个 init;DOMContentLoaded 后再补扫一次并暴露 `window.AKSRTCaptchaState.rescan()` 供未来 ajax 注入使用。保持 vanilla JS、无新依赖。
|
||
|
||
对应 PHP 渲染端瘦身:`aksrt_render_captcha()` 只输出
|
||
1. 原 wrapper 结构不变(`.aksrt-captcha-wrap` + `#uid` box + `#vid` captcha_verified 隐藏域),
|
||
2. wrapper 上挂 `data-aksrt-captcha-config`(`esc_attr(wp_json_encode($js_config))`),
|
||
3. 删除内联 `<script>` 与逐次 `<link rel="stylesheet">`。
|
||
|
||
TOKEN_FIELDS 常量、i18n 字符串原样进 JS 文件(与仓库其它 bundle 内硬编码中文一致)。
|
||
|
||
## 3. 构建与后台(P2-10 + bundle 接线)
|
||
|
||
- `tools/build-public-assets.mjs`:`publicScripts` 追加 `'assets/js/captcha-front.js'`;`cssBundles['public.css']` 追加 `'assets/css/shared/captcha.css'`。走既有 bundle 版本机制,无需新增 enqueue 代码。
|
||
- `SchemaPermissions.php`:删除 'mode' 字段定义(L32-34,单选项 always 的死字段)。
|
||
- `assets/admin/src/schema/sections/permissions/index.js`:删除 `mode` 的 defaults(L18)与字段定义(L50-56)。
|
||
- `SchemaProvider.php` L403:归一化白名单去掉 `'mode'`;`write_section_settings()` 更新 `aksrt_captcha_config` 后调用新助手 `aksrt_captcha_config_reset()` 清静态缓存(function_exists 守卫,与现有 captcha 专用块并排)。
|
||
- DB 里残留的 `mode` 键不做迁移清洗(读路径白名单已忽略它,符合"不做迁移"约束)。
|
||
|
||
## 4. inc/modules/captcha.php — 后台警告与缓存
|
||
|
||
- **P0-3**:新增顶层 `add_action('admin_notices', ...)`:`manage_options` 权限 + `enabled` 为真 + `active_provider` 非空 + `aksrt_captcha_provider_is_configured()` 为假时,输出 `notice-error` 横幅,文案指向「功能&权限 → 人机验证」补全配置(复用现有 misconfig 提示文案)。前台行为不变(保持放行)。
|
||
- **P2-11**:`aksrt_get_captcha_config()` 加 `static $cache`;新增 `aksrt_captcha_config_reset()`;写入路径(SchemaProvider)调用 reset。`aksrt_get_captcha_status_summary()` 的 12 场景循环随之受益。
|
||
|
||
## 5. 新契约测试 tests/widget-system/captcha-cloud-contract.test.cjs
|
||
|
||
仿 toast-contract 的正则断言风格:
|
||
- `captcha.php`:不匹配 `curl_init|CURLOPT_SSL_VERIFYPEER|machine-verification|slidercaptcha|imagecaptcha`;匹配 `wp_remote_post`(≥4 处)、`wp_generate_uuid4`、`'timeout'\s*=>\s*5`、`aksrt_captcha_pass_`;渲染函数不匹配 `/<script|<link/`(内联抽取完成)
|
||
- `captcha-front.js` 存在且含 `AKSRTCaptchaState`、`data-aksrt-captcha-config`
|
||
- `build-public-assets.mjs` 的 publicScripts 含 captcha-front.js、public.css 含 shared/captcha.css
|
||
- `SchemaPermissions.php` 与 admin `index.js` 的 captcha 段不匹配 `mode`
|
||
- `SchemaProvider.php` 不匹配 `'mode'`
|
||
|
||
## 6. 验证(不做视觉验收)
|
||
|
||
1. `php -l` 全部改动的 PHP 文件
|
||
2. `node --check` captcha-front.js
|
||
3. `node tools/build-public-assets.mjs` 重建 bundle
|
||
4. `grep` 全仓清扫:无 `curl_init`、无 `'mode'`(captcha 相关文件)、无 legacy 标记
|
||
5. `node --test tests/widget-system/*.test.cjs` 全量跑,预期仅存量 page-display-contract 一项失败(与本次无关,已验证在 HEAD 上同样失败)
|
||
|
||
## 明确不做
|
||
|
||
- 不做视觉验收/浏览器实测(按要求)
|
||
- 不写新旧配置迁移、不清洗 DB 残留 `mode` 键
|
||
- 不动腾讯 trerror 容灾票据策略(维持拒绝)
|
||
- 不做阿里云签名 V3 升级、Turnstile appearance/retry 配置项(列为后续可选项)
|
||
- 不动 `ExtensionController` 的 extensions 状态端点(SPA 未消费属另一话题)
|
||
|
||
## 建议提交拆分(如需提交)
|
||
|
||
1. `fix(captcha): use WP HTTP API with TLS verification for tencent`
|
||
2. `feat(captcha): short-lived download pass + turnstile binding + error hardening`
|
||
3. `refactor(captcha): extract inline runtime to captcha-front.js bundle`
|
||
4. `chore(captcha): drop dead mode field, config cache, contract tests`
|