- 开发工具
- CLI
- 配置管理
【免费下载链接】chezmoi
Manage your dotfiles across multiple diverse machines, securely.
本篇技术指南讲解 chezmoi 点文件管理器中内置的模板函数protonPassJSON:它以 Proton Pass 的pass://URI 为入参,调用 Proton Pass CLI 并以 JSON 结构返回该条目下的全部字段数据,从而在点文件模板中按需取用密码、WiFi 凭据、TOTP 等敏感信息。读完本文,你将掌握protonPassJSON的调用语法、返回结构、缓存与安全语义,并能结合仓库源码与测试用例确认其真实行为边界。
函数签名与核心用途
protonPassJSON是 chezmoi 内置的 Proton Pass 模板函数族(protonPass*)之一,与protonPass、protonPassAttachment共同构成 Proton Pass 集成能力。其文档定义如下:
protonPassJSON *uri*- 入参:一个
pass://形式的 Proton Pass 条目 URI; - 返回值:与该 URI 对应的结构化数据(JSON 对象),可直接用模板语法逐层取字段。
典型示例(来自官方文档 protonPassJSON.md):
{{ (protonPassJSON "pass://$SHARE_ID/$ITEM_ID").item.content.content.key.password }}其中$SHARE_ID、$ITEM_ID是占位符,实际使用时替换为真实的共享库(share)ID 与条目(item)ID。该表达式依次穿透 JSON 层级:item→content→content→ 具体条目类型(如Wifi、Login、key等)→ 目标字段,最终得到密码等敏感值并写入模板输出。
返回结构:JSON 对象而非文本
protonPassJSON与protonPass的关键区别在于返回类型:
protonPass返回pass-cli item view的原始文本输出(string);protonPassJSON则在调用时追加--output=json参数,并将输出解析为 Go 的map[string]any后返回,因此在模板中可以直接进行结构化字段访问。
从实现看,internal/cmd/protonpasstemplatefuncs.go 中:
func (c *Config) protonPassJSONTemplateFunc(item string) any { chezmoi.SkipTemplateIf(c.skipSecrets) args := []string{"item", "view", item, "--output=json"} output := mustValue(c.protonPassOutput(args)) var result map[string]any must(json.Unmarshal(output, &result)) return result }即底层执行的是pass-cli item view <uri> --output=json,随后用标准库encoding/json反序列化为 map。这意味着 JSON 中数组会变为[]any,对象会变为map[string]any,数字按 Go JSON 规则解码。
以仓库测试 protonpass.txtar 中模拟的pass-cli输出为例,调用protonPassJSON "pass://MyVault/My-Wifi-Item"会返回形如:
{ "item": { "id": "...", "share_id": "...", "vault_id": "...", "content": { "title": "My Wifi", "content": { "Wifi": { "ssid": "My Wifi SSID", "password": "MyWifiPassword", "security": "WPA2", "sections": [] } }, "extra_fields": [] }, "state": "Active", "create_time": "2025-10-27T11:11:22" }, "attachments": [] }因此模板中可用链式访问精确取值,且不需要额外trim(protonPassJSON返回的是解析后的结构而非带换行的原始文本)。
底层调用链:URI 如何变成密码
从源码可以梳理protonPassJSON的完整调用链(internal/cmd/protonpasstemplatefuncs.go):
- 模板引擎按 internal/cmd/config.go 中注册的映射
"protonPassJSON": c.protonPassJSONTemplateFunc找到实现; - 函数将入参拼接为
pass-cli item view <uri> --output=json参数列表; protonPassOutput以exec.Command启动pass-cli,并透传 stdin(cmd.Stdin = os.Stdin)、透传 stderr(cmd.Stderr = os.Stderr)——前者让 CLI 可以交互式解锁密钥库或确认操作,后者让错误信息直接呈现;- 命令失败时通过
newCmdOutputError包装错误并 panic,模板渲染随之终止并暴露给用户; - 成功后将 stdout 作为该参数组合的缓存结果返回。
可验证的运行示例(与测试脚本等价):
chezmoi execute-template '{{ (protonPassJSON "pass://MyVault/My-Wifi-Item").item.content.content.Wifi.password }}' # 输出: MyWifiPassword对应测试断言位于 internal/cmd/testdata/scripts/protonpass.txtar。
命令配置与 doctor 诊断
protonPassJSON实际调用的可执行文件名通过配置项protonPass.command控制,默认值为pass-cli:
# ~/.config/chezmoi/chezmoi.yaml protonPass: command: pass-cli # 默认值,可改为绝对路径或 PATH 中的别名证据来源:
- internal/cmd/config.go:
ProtonPass: protonPassConfig{Command: "pass-cli"}; - internal/cmd/config.go:
ProtonPass protonPassConfig json:"protonPass" mapstructure:"protonPass" yaml:"protonPass"; - assets/chezmoi.io/docs/reference/configuration-file/variables.md.yaml:
protonPass.command默认值pass-cli,类型为字符串。
chezmoi doctor会检查该命令是否存在及版本是否合规(internal/cmd/doctorcmd.go):
- 检查项名称
protonpass-command; - 未配置时报告
checkResultWarning,二进制不存在时报告checkResultInfo; - 通过
--version验证输出匹配^Proton Pass CLI (\d+\.\d+\.\d+)。
因此即使protonPassJSON首次调用失败,也可先用chezmoi doctor快速定位是命令缺失、版本不匹配还是 URI 错误。
安全语义与缓存行为
protonPassJSON受skipSecrets开关约束:函数入口调用chezmoi.SkipTemplateIf(c.skipSecrets)(internal/cmd/protonpasstemplatefuncs.go)。当用户启用跳过密钥(如--skip-secrets或相关配置)时,该函数会静默跳过渲染,防止在无需密钥的场合(如公开模板演练)泄露凭据。
同时,protonPassOutput内置了输出缓存(internal/cmd/protonpasstemplatefuncs.go):
key := strings.Join(args, "\x00") if data, ok := c.ProtonPass.outputCache[key]; ok { return data, nil }缓存键由全部参数以\x00连接而成。这意味着在**同一次 chezmoi 运行(apply / execute-template 等)**中,多次以相同 URI 调用protonPassJSON只会真正执行一次pass-cli,后续命中缓存,显著减少对外部密码管理器的重复调用。每次进程退出后缓存清空,不会跨运行持久化。
另外值得注意:若模板同时使用protonPass(文本输出)与protonPassJSON(JSON 输出),两者参数不同(后者带--output=json),因此缓存键不同,会各自独立执行一次。
与同族函数的分工
Proton Pass 模板函数族在 internal/cmd/config.go 中统一注册,三者分工互补:
| 函数 | 入参 | 返回 | 典型场景 |
|---|---|---|---|
protonPass | pass://$SHARE_ID/$ITEM_ID/$FIELD | 原始文本(string) | 直接取单个字段值,如{{ protonPass "pass://S/I/password" }} |
protonPassJSON | pass://$SHARE_ID/$ITEM_ID | JSON 对象(map) | 取多字段、嵌套字段、数组等结构化数据 |
protonPassAttachment | share-iditem-idattachment-id | 附件内容(string) | 下载并读取条目附件,如 SSH 私钥 |
protonPassAttachment同样具备缓存(attachmentCache,键为shareID\x00itemID\x00attachmentID),且因pass-cli输出冗长,默认不连接 stdout/stderr,仅在--debug时透传(internal/cmd/protonpasstemplatefuncs.go)。
实战:在点文件模板中组合使用
protonPassJSON最常见的落地方式是配合 Go 模板的条件与遍历语法,动态生成仅含当前机器所需凭据的配置文件:
{{- $item := protonPassJSON "pass://MyVault/My-Wifi-Item" -}} # /etc/wpa_supplicant.conf 模板片段 network={ ssid="{{ $item.item.content.content.Wifi.ssid }}" psk="{{ $item.item.content.content.Wifi.password }}" key_mgmt=WPA-PSK }实现要点:
- 用
{{- $item := ... -}}将返回值暂存到模板变量,避免多次调用(也避免多次命中缓存的边际开销); - 每一层
.item.content.content.<类型>.<字段>的路径由pass-cli --output=json的真实结构决定,可用chezmoi execute-template配合debug先观察原始 JSON:chezmoi execute-template '{{ protonPassJSON "pass://MyVault/My-Wifi-Item" | toJson }}'借助
toJson模板函数将 map 序列化输出,即可核对字段路径; - 若取不到字段,错误会由
mustValue/must在模板渲染期直接暴露,便于排查。
总结
protonPassJSON是 chezmoi 与 Proton Pass 深度集成的结构化取数入口:它以pass://URI 定位条目,经由pass-cli item view --output=json获取 JSON,再返回可直接链式访问的模板对象。源码确认其具备 stdin 透传(支持 CLI 交互解锁)、skipSecrets跳过语义与进程内输出缓存三项关键行为,chezmoi doctor提供了独立的命令健康检查。对于需要在多台机器上安全同步点文件、又不希望把明文密码写进仓库的用户,protonPassJSON提供了「模板即查询」的优雅方案。
更多相关参考:protonPass文本函数见 protonPass.md,附件函数见 protonPassAttachment.md,模板函数总览见 index.md,测试用例见 protonpass.txtar。
- 开发工具
- CLI
- 配置管理
【免费下载链接】chezmoi
Manage your dotfiles across multiple diverse machines, securely.
相关推荐
免费苹方字体包快速接入指南:6种字重双格式,一次终结跨平台字体混乱
免费苹方字体包快速接入指南:6种字重双格式,一次终结跨平台字体混乱 你在公司群里被前端同事艾特:"这个页面到我电脑上怎么变成宋体了?"点开截图一看,标题塌了、正
开发工具CLI配置管理chezmoi 模板函数 `passFields` 完全指南:从 pass 密码库提取结构化键值数据
chezmoi 模板函数 passFields 完全指南:从 pass 密码库提取结构化键值数据 导读 passFields 是 chezmoi 内置的模板函数
开发工具CLI配置管理chezmoi 模板函数 `keeperDataFields`:从 Keeper Commander CLI 提取结构化凭据数据
chezmoi 模板函数 keeperDataFields :从 Keeper Commander CLI 提取结构化凭据数据 keeperDataFields
开发工具CLI配置管理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考