Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions plugins/share-sanitizer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist/
node_modules/
10 changes: 10 additions & 0 deletions plugins/share-sanitizer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# 更新日志

## 0.1.0

- 提供本地优先的文本与图片脱敏工作台。
- 为 ZTools 2.4+ 新增有界的原生 MCP 检测与脱敏工具,并在旧版宿主上安全降级。
- 将脱敏调整为“全部完成或整体拒绝”;超过 500 项的预览会报告明确的截断总数,并对序列化 MCP 响应执行 512 KiB 上限。
- 根目录改用源文件入口,修复相对 `development.main` 无法被 ZTools 正确加载的问题,并增加 14.5 MB 发布体积安全门禁。
- 对齐 ZTools 宿主的 `over`、`img` 和 `files` 启动载荷契约,选中的文件系统路径始终保留在 preload 边界内。
- 将人类界面、状态提示、确认对话框和入口错误提示完整本地化为简体中文。
31 changes: 31 additions & 0 deletions plugins/share-sanitizer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 分享脱敏台

界面、状态提示、确认对话框和图片导出提示均使用简体中文;MCP 工具名、schema 字段和错误码保持稳定,便于 Agent 调用。

这是一款本地优先的分享前审查工具,用于在文本或图片对外分享前移除敏感数据。

它可检测电子邮箱、中国手机号和身份证号、IPv4 地址、绝对路径、Bearer/API 凭据以及 JWT。用户可关闭特定规则,也可将已确认安全的值加入白名单。图片会绘制到新的画布(`canvas`),从而移除原图元数据;用户还可手动添加矩形遮罩。浏览器 OCR 是明确的可选能力:当 `TextDetector` 不可用时,界面会明确说明,不会声称 OCR 已完成。

## 安全与跨平台

- 检测器由纯 JavaScript 实现,会在不依赖当前宿主操作系统的情况下测试 POSIX、Windows 和 Linux 路径形式。
- 精简的 preload 桥仅在宿主支持时暴露剪贴板操作 `copyText` 和 `copyImage`,并且只会从 `onPluginEnter` 转发通过校验的文本或图片内容;渲染层不会获得文件系统路径。
- ZTools 的 `over`、`img` 和单文件载荷会按类型处理。宿主选择的文本文件最多按 UTF-8 解码 1 MiB,图片最多进行 20 MiB 的签名检查;符号链接、目录、不支持的扩展名或选择后发生变化的文件均会按失败关闭处理。
- 人工输入上限为 1 MiB。检测预览最多展示 500 个发现项,并明确标记预览已截断;完整脱敏最多处理 10,000 个匹配,超过上限时会拒绝整个操作,而不是返回只完成一部分的结果。
- 不使用网络、外部字体、原生附加组件或 shell 命令。

## Agent / MCP 使用

ZTools 2.4 及更高版本可将清单中的 `detect_text` 和 `redact_text` 工具暴露给 Agent,完整名称分别为 `share_sanitizer_detect_text` 和 `share_sanitizer_redact_text`。两者与人工界面共用同一套本地检测器。检测输入的 UTF-8 上限为 512 KiB;脱敏输入上限为 448 KiB,以确保普通输出与有界证据之和不超过宿主边界。白名单最多 200 项、总大小最多 64 KiB;替换文本最多 64 个字符。替换文本自身必须安全,拼接入原文后的完整输出也会按同一启用规则和白名单再次检查;任一非白名单敏感值都会拒绝整个请求,避免借由边界拼接把刚移除的敏感值重新写回输出。校验后的序列化输入还有 768 KiB 的硬上限。未知字段、规则名、非布尔规则开关以及尝试改写内部上限的输入均会被拒绝。

检测发现项只包含 `type`、`start`、`end` 和 `confidence`,以及汇总计数;匹配到的敏感原值绝不会出现在发现项中。Agent 证据最多保留 500 项,并提供 `counts.total`、`counts.returned` 和 `truncated`;`counts.byType` 描述已返回的证据。当检测扫描被截断时,`counts.total` 为 `null`,`counts.totalAtLeast` 表示已证明的数量下界。脱敏必须处理完所有匹配后才会返回,并报告精确总数;超过 10,000 个匹配的完整脱敏会被拒绝。最终 MCP 结果的序列化上限为 512 KiB,因此替换或 JSON 转义导致的体积膨胀会被拒绝,而不会产生数 MiB 的响应。

脱敏工具会返回清理后的文本,白名单中的值则会按设计原样保留。因此调用方和 Agent 必须控制清理后文本的传播范围;发现项仍不会回显白名单项或匹配原值。旧版 ZTools 宿主没有 `registerTool` 时,人工界面仍可使用,但不会提供 MCP 工具。

运行 `npm test`、`npm run build` 和 `npm run verify-dist` 进行验证。在实体 Windows/macOS/Linux ZTools 宿主中的运行时加载仍待测试。

## 本地 ZTools 开发

在 ZTools 开发者工具中添加根目录的 `plugin.json`。其 `main`、`preload` 和 `logo` 均指向可读的源文件,因此插件可通过 ZTools 的文件 URL 加载器直接打开。不要添加相对路径的 `development.main`:当前 ZTools 版本会将该字段直接传给 `loadURL`,而相对文件系统路径并不是有效 URL。仓库构建仍会生成并打包可独立发布的 `dist/` 清单。

`npm run build` 还会对未压缩的 `dist/` 执行 14.5 MB(14,500,000 字节)安全门禁,为 15 MB 的插件大小限制预留打包开销。
1 change: 1 addition & 0 deletions plugins/share-sanitizer/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions plugins/share-sanitizer/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions plugins/share-sanitizer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "share-sanitizer",
"version": "0.1.0",
"private": true,
"type": "commonjs",
"engines": {
"node": ">=16"
},
"scripts": {
"test": "node --test",
"build": "node --test && node scripts/build.mjs && node scripts/verify-dist.mjs",
"verify-dist": "node scripts/verify-dist.mjs"
}
}
72 changes: 72 additions & 0 deletions plugins/share-sanitizer/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"name": "share-sanitizer",
"title": "分享前脱敏",
"version": "0.1.0",
"description": "在分享前检查并脱敏敏感文本和图片。",
"author": "harris",
"main": "src/ui/index.html",
"logo": "logo.svg",
"preload": "preload/index.cjs",
"platform": ["darwin", "win32", "linux"],
"categories": ["productivity", "text", "media"],
"features": [{"code": "sanitize-share", "explain": "在分享前脱敏选中的文本、文件或图片。", "icon": "logo.svg", "cmds": ["分享脱敏", "敏感信息清理", {"type":"files","fileType":"file","label":"脱敏文件","extensions":["txt","md","json","log","png","jpg","jpeg","webp"],"maxLength":1}, {"type":"img","label":"脱敏图片"}, {"type":"over","label":"脱敏选中文字","minLength":1,"maxLength":200000}]}],
"tools": {
"detect_text": {
"title": "检测分享文本中的敏感信息",
"description": "离线检测文本并仅返回不含原值的类型、位置、置信度和统计。",
"inputSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"text": {"type": "string", "maxLength": 524288},
"whitelist": {"type": "array", "maxItems": 200, "items": {"type": "string", "maxLength": 4096}},
"enabled": {
"type": "object",
"additionalProperties": false,
"properties": {
"email": {"type": "boolean"},
"phone_cn": {"type": "boolean"},
"ipv4": {"type": "boolean"},
"win_path": {"type": "boolean"},
"posix_path": {"type": "boolean"},
"bearer": {"type": "boolean"},
"api_key": {"type": "boolean"},
"jwt": {"type": "boolean"},
"id_cn": {"type": "boolean"}
}
}
},
"required": ["text"]
}
},
"redact_text": {
"title": "脱敏分享文本",
"description": "离线替换敏感片段,并返回清理后的文本及不含原值的发现统计;replacement 与最终拼接输出均不得包含任何启用规则可识别的非白名单敏感值。",
"inputSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"text": {"type": "string", "maxLength": 458752},
"replacement": {"type": "string", "maxLength": 64, "description": "可选安全替换文本;若自身或与上下文拼接后的输出命中任一启用规则且不在白名单中,则拒绝整个请求。"},
"whitelist": {"type": "array", "maxItems": 200, "items": {"type": "string", "maxLength": 4096}},
"enabled": {
"type": "object",
"additionalProperties": false,
"properties": {
"email": {"type": "boolean"},
"phone_cn": {"type": "boolean"},
"ipv4": {"type": "boolean"},
"win_path": {"type": "boolean"},
"posix_path": {"type": "boolean"},
"bearer": {"type": "boolean"},
"api_key": {"type": "boolean"},
"jwt": {"type": "boolean"},
"id_cn": {"type": "boolean"}
}
}
},
"required": ["text"]
}
}
}
}
Loading
Loading