安全与验证
最后更新于 2026年8月11日
Comoji 需要辅助功能和输入监控权限。这是 macOS 上最敏感的两项权限,而“相信我们,一切都在本地”算不上一个答案。这个页面的存在,就是为了让你不必只听我们的一面之词:下面列出了应用可能连接的每一个主机、每次连接的触发条件,以及在你打字时于自己电脑上观察 Comoji 的确切命令。
简而言之:你的按键永远不会离开你的 Mac。不会发给我们,也不会发给任何人。Comoji 没有账户、没有遥测、没有分析,也没有崩溃报告工具。它发出的网络请求只有下面列出的四种,除了 GIF 选择器自己的搜索框,其中没有任何一种会携带你输入的内容。
更喜欢跟着教程做?如何一步步验证 Comoji 仅在本地运行提供了截图和可直接复制粘贴的命令。
每项权限的用途
macOS 自己的权限提示只会告诉你某个应用想要哪项权限,却从不说明应用会用它做什么。所以,具体来说:
输入监控
- 用途:一个键盘事件监听(event tap),用来留意以冒号开头的关键词,例如
:liz。字符会暂存在一个很小的内存缓冲区中,关键词一结束(空格、Esc、点击别处,或接受了某个匹配)就会立即丢弃。 - 绝不用于:记录、存储或传输你输入的内容。缓冲区从不写入磁盘、从不记入日志,也从不发送到任何地方。如果处理按键的代码中出现任何网络 API 或远程 URL,应用自己的测试套件就会让构建失败。
- 完全不监听:安全(密码)文本输入框,以及一份内置的排除列表(涵盖密码管理器、终端和远程/虚拟机客户端),还有你在“偏好设置 › 隐私”中自行添加的任何应用或网站。
辅助功能
- 用途:向 macOS 询问哪个文本输入框拥有键盘焦点、其光标在屏幕上的位置,以便建议弹出窗口出现在正确的地方;以及把选中的表情输入回那个输入框(模拟退格,再加上一次短暂的剪贴板粘贴,之后会恢复你原来的剪贴板内容)。
- 绝不用于:读取输入框的内容、你的文稿、你的消息或其他窗口。
完整的网络访问范围
这就是完整的列表。如果你发现 Comoji 连接了不在列表中的主机,那就是 bug,我们希望你通过 support@comoji.io 告诉我们。
storage.googleapis.com
- 内容: 更新源(一个 Sparkle appcast)和新版本的 DMG。两者都存放在 Comoji 的 Firebase Storage 存储桶中。
- 时机: 后台更新检查和下载,以及“检查更新…”菜单项。在“偏好设置”中关闭“让 Comoji 保持最新”后,只有在你主动要求时才会发生。
- 请求中包含什么: 一个普通的 GET 请求。Sparkle 的用户代理中包含应用名称和你当前使用的版本。
fonts.gstatic.com
- 内容: 贴纸图案(Google 的 Noto Animated Emoji),用于应用中尚未内置的贴纸。
- 时机: 在 /sticker 选择器中选择一个未内置的贴纸时。首次使用后会缓存在你的 Mac 上,所以每个贴纸只会发生一次。
- 请求中包含什么: 一个普通的 GET 请求,获取一个以表情码位命名的图片文件。
api.giphy.com
- 内容: 为 /gif 选择器提供 GIF 搜索和热门结果。
- 时机: 打开 /gif 时,以及你在该选择器中输入的每一次搜索。绝不会自动发生:不用 /gif,就没有请求。
- 请求中包含什么: 只有你在 GIF 选择器搜索框中输入的文字、Comoji 的 GIPHY API 密钥,以及当 Comoji 使用英语以外的语言时,让结果匹配该语言的语言代码(例如 zh-CN)。你在 Mac 上其他任何地方输入的内容都不会包含在内。
*.giphy.com
- 内容: GIF 文件本身,来自 GIPHY 的 CDN(media0–media4.giphy.com)。
- 时机: 显示或插入你已经请求过的搜索结果中的 GIF 时。
- 请求中包含什么: 一个普通的 GET 请求,获取搜索结果中指定的确切 GIF URL。
没有别的了
没有分析端点,没有遥测,没有错误报告,没有许可证服务器,也没有账户系统。安装 Comoji,从不打开 /gif 或 /sticker,并关闭自动更新检查,那么只要应用在运行,它发出的网络请求就是零。
这份列表不只是对应用的描述,更是应用遵守的规则。并非每个 URL 都写在源代码里:GIF 文件本身的地址来自 GIPHY 的搜索响应。每一次这样的获取在发出请求之前,都会先与上面的列表比对,不匹配就丢弃。重定向也会以同样的方式检查,所以服务器回复“改去这里”也无法把我们引到别处。即使搜索响应被篡改或劫持,也无法让 Comoji 连接本页面未列出的主机。
下面这些主机名也出现在应用中,但 Comoji 从不获取它们。它会把 URL 交给 macOS,由你的浏览器加载页面:www.comoji.io, www.mattsenter.com, www.senter.net, www.stockcar.app, www.premail.pro, www.burly.click, www.beeready.buzz, www.highwire.news, www.orga.bot, www.weatherling.app, www.seedmatrix.com。
如何亲自验证
下面的每条命令都是只读的,可以放心运行。在 Comoji 运行时,把它们粘贴到“终端”中。(如果你安装的是开发版本,进程名是 ComojiDev 而不是 Comoji。)
1. 在打字时观察它的网络连接
首先确认 Comoji 确实在运行,并获取它的进程 ID:
pgrep -x Comoji你应该会得到一个数字。如果什么都没返回,说明 Comoji 没有在运行(它是菜单栏应用,所以请看菜单栏而不是程序坞),这时下面的命令无论它有没有联网,都会报告没有连接。请先拿到 PID,否则后面的步骤什么都证明不了。
lsof 会列出一个进程打开的网络套接字。打开“信息”,输入 :fire 并按几次 Tab,然后运行:
lsof -nP -i -a -p "$(pgrep -x Comoji)"预期完全没有输出。没有输出意味着该进程没有打开任何网络连接,这正是我们的声明,并且经过了直接测试。
要在使用过程中持续观察,请在一个空闲的“终端”窗口中运行以下命令,然后在另一个应用里打一会儿字:
while :; do
printf '%s ' "$(date +%T)"
lsof -nP -i -a -p "$(pgrep -x Comoji)" | tail -n +2 | awk '{print $9}' | paste -sd' ' -
echo
sleep 2
done无论你打多少字,这一行都保持为空。然后打开 /gif 搜索点什么:你会看到 api.giphy.com 和一个 giphy.com CDN 主机出现,而且只在这时出现。
2. 进出的总字节数
nettop 会显示每个进程的累计流量,因此能捕捉到 lsof 两次采样之间可能漏掉的短暂连接:
nettop -P -p "$(pgrep -x Comoji)"打几分钟字,不要碰 GIF 和贴纸选择器。bytes_in 和 bytes_out 两列会保持为零。按 q 退出。
3. 从发布的二进制文件中读出主机名
运行中的进程只能连接它知道的地方。你可以直接从你下载的应用中提取 URL:
strings -a /Applications/Comoji.app/Contents/MacOS/Comoji \
| grep -Eo 'https?://[A-Za-z0-9._-]+' | sort -u
/usr/libexec/PlistBuddy -c 'Print :SUFeedURL' \
/Applications/Comoji.app/Contents/Info.plist有两点需要坦白说明,好让结果和你实际看到的一致。第一,api.giphy.com 是由主机名拼接而成的,并没有作为完整 URL 存储,所以它不会出现在第一个列表中。请用 strings -a … | grep -Eo '[a-z0-9.-]*giphy\.com' 直接搜索它;这个模式只匹配主机名,因此不会打印出同样随应用包附带的 API 密钥。第二,内置的 Sparkle 更新框架在 Contents/Frameworks/Sparkle.framework 中带有自己的文档 URL(sparkle-project.org、andymatuschak.org);这些是第三方库中的字符串,并不是 Comoji 会连接的主机。
4. 用防火墙拦截它,看看什么会失效
最有力的检验是出站防火墙。LuLu 免费且开源;Little Snitch 是商业软件中的标杆。把任意一个设置为对每个出站连接发出提醒,然后拒绝 Comoji 的所有连接。表情自动补全会一如既往地工作,永远如此,因为它从来不需要网络。唯一会失效的,是更新检查以及远程的贴纸或 GIF 图案。
5. 确认应用确实出自我们之手且未被修改
Comoji 使用 Apple Developer ID 签名,并经过 Apple 公证。以下命令可以验证你磁盘上的副本没有被篡改:
codesign -dv --verbose=4 /Applications/Comoji.app
spctl -a -vvv -t exec /Applications/Comoji.app
codesign -d --entitlements - /Applications/Comoji.app我们决定做什么,以及不做什么
显而易见的问题是:为什么不干脆把整个项目开源?下面是我们的真实立场,让你可以评判这个答案,而不是去猜。完整的理由作为一份架构决策记录(docs/adr/0001-verifiable-local-processing.md)保存在代码仓库中。
- 已完成:公布确切的网络访问范围。即上面的列表,它同样显示在应用的“偏好设置 › 隐私”中,与应用编译时所依据的声明来自同一来源,并在运行时据此强制执行,所以即使别人的服务器把某个 URL 交给应用,也无法连接到未公开的主机。
- 已完成:自行验证说明。即本页面和其中链接的分步教程。
- 已完成:在 CI 中强制执行这项声明。每个拉取请求和每次发布都会在 macOS 运行器上运行应用的测试套件(
.github/workflows/app-ci.yml,并且在release.yml中签名任何东西之前会再运行一次)。该测试套件会扫描实际的源代码,如果出现本页面未公开的主机,或者处理按键的代码中出现任何网络 API 或远程 URL,测试就会失败。违反任一规则的构建都无法合并,也无法发布。 - 暂不采纳:只开源输入处理部分。只公开事件监听、关键词缓冲区和匹配器,会是一个实实在在的信任信号,而且这部分也没有商业价值。我们暂时不这么做,理由是诚实的,而不是充分的:一个无法证明与公证后二进制文件中代码一致的公开子集,证明力比看上去要弱,而要做好这件事就需要可重现构建(见下文)。我们宁愿先提供你可以在实际下载的二进制文件上执行的验证。这一点可以重新考虑,而且输入处理部分会是我们第一个公开的内容。
- 暂不采纳:可重现构建和付费安全审计。两者都是可信度最高的选项,但成本都超过了这个项目目前的收入。这是推迟,而不是放弃:一旦收入允许,下一步就是进行付费的第三方审计并公布摘要,摘要也会发布在这里。
如果你验证了其中任何一项,发现有与本页面内容相矛盾的地方,请发邮件至 support@comoji.io,我们会修正页面或应用,看哪一个出了错。
另请参阅隐私政策,了解 Comoji 在你的 Mac 上本地存储了哪些数据。