拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

gopass cat 命令:借助 STDIN/STDOUT 管道安全存取二进制密码数据

gopass cat 命令:借助 STDIN/STDOUT 管道安全存取二进制密码数据
  • 应用安全
  • 开发工具

【免费下载链接】gopass

The slightly more awesome standard unix password manager for teams

项目地址:https://gitcode.com/gh_mirrors/go/gopass
点击查看免费下载

gopass cat是 gopass 密码管理器中面向二进制数据流的专用命令:它把 STDIN 上的任意数据流(文本、图片、证书、密钥文件等)Base64 编码后存入密码库,并把库中已编码的条目解码回 STDOUT 输出,实现"管道进、管道出"的存取闭环。读完本文,你将掌握gopass cat的完整语法、三种工作模式、底层存储格式(MIME 风格的元数据 + Base64 载荷)以及它与insert、show等命令的本质区别,能够安全地把非文本敏感文件纳入 gopass 统一管理。

命令概览:为什么需要一个"二进制版 cat"

gopass 的密码库底层以文本形式组织内容,常规的insert命令会把输入解析成"首行密码 + 键值对"结构(详见下文对比)。但当你需要存储图片、SSH 私钥、加密证书、压缩包等二进制数据时,这种解析会破坏原始字节。为此 gopass 提供了cat命令——它的设计定位正是"把密码从 STDIN 管道进来、从 STDOUT 管道出去",并为了兼容二进制数据,在入库前对数据流做编码处理。

官方文档 docs/commands/cat.md 明确指出:

Thecatcommand is used to pipe password in and out of STDIN and STDOUT respectively. As it is intended to be used with binary data, it encodes the># 从 STDIN 写入:echo 一段文本,编码后存入 test/new $ echo "test" | gopass cat test/new # 从 STDOUT 读出:解码 test/new 并打印原始内容 $ gopass cat test/new

命令只接受一个位置参数[secret](即目标条目名),例如test/new。如果未提供名称,源码 internal/action/binary.go 会直接返回NoName级别的用法错误:Usage: gopass cat <NAME>。

三种工作模式

依据文档,cat支持三种操作模式:

  1. 创建新条目:把 STDIN 的数据流编码后写入一个尚不存在的条目;
  2. 更新已有条目:把 STDIN 的数据流编码后覆盖同名的已有条目;
  3. 读取条目:把密码库中已编码的数据解码后回显到 STDOUT。

模式由输入来源自动判定:当 STDIN 是管道/重定向(非字符设备)时走"写入"分支,当 STDIN 是交互式终端时走"读取"分支。源码 internal/action/binary.go 用binstdin.Stat()检查info.Mode()&os.ModeCharDevice == 0来判断是否为管道输入:

// if content is piped to stdin, read and save it. if info.Mode()&os.ModeCharDevice == 0 { debug.Log("Reading from STDIN ...") content := &bytes.Buffer{} if written, err := io.Copy(content, binstdin); err != nil { return exit.Error(exit.IO, err, "Failed to copy after %d bytes: %s", written, err) } ... }

io.Copy保证了任意长度的数据流都能被完整读入,测试 internal/action/binary_test.go(TestBinaryCatSizes)专门从 1 KiB 一直循环到bufio.MaxScanTokenSize*2(约 1 MiB 量级)验证"输入与输出逐字节一致"。

完整实战示例

官方文档给出了一个从写入、查看存储格式到读出的完整闭环示例:

$ echo "234" | gopass cat test/new $ gopass show -f test/new Secret: test/new content-disposition: attachment; filename="STDIN" content-transfer-encoding: Base64 MjM0Cg== $ gopass cat test/new 234

逐段解读:

  • echo "234" | gopass cat test/new:把字符串234\n编码并写入条目test/new;
  • gopass show -f test/new:强制以原始形式查看存储内容,可以看到条目由两段 MIME 风格的元数据和一段 Base64 载荷构成;MjM0Cg==正是234\n的 Base64 编码;
  • gopass cat test/new:解码MjM0Cg==并在 STDOUT 打印出原始的234。

存储格式:Base64 编码与 MIME 元数据

文档说明:cat 从 STDIN 读取二进制流,将其Base64 编码后存入密码库,并附上关于输入来源与所用编码(目前仅支持 Base64)的元数据。这一设计的具体实现位于 internal/action/binary.go 的secFromBytes函数:

sec := secrets.NewAKV() sec.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filepath.Base(src))) sec.Set("Content-Transfer-Encoding", "Base64") var written int encoder := base64.NewEncoder(base64.StdEncoding, sec) n, err := encoder.Write(in) ... n, err = sec.Write([]byte("\n"))

要点拆解:

  • 条目载体:使用secrets.NewAKV()构造的 AKV(attributes-key-value)格式条目,其结构定义在 pkg/gopass/secrets/akv.go,内部持有密码字段、键值对映射和原始字符串缓冲区;
  • 来源元数据:Content-Disposition: attachment; filename="STDIN",文件名取输入来源的filepath.Base(从管道输入时即为STDIN,从文件拷贝时为文件名);
  • 编码元数据:Content-Transfer-Encoding: Base64,声明载荷的编码方式;
  • 载荷编码:使用 Go 标准库encoding/base64的StdEncoding将原始字节写入条目,并在末尾追加一个换行符,形成上文示例中MjM0Cg==那样的单行 Base64 文本。

写入条目的提交信息固定为"Read secret from STDIN"(见 internal/action/binary.go),在基于 git 的存储后端中,这条信息会成为该次变更的 commit message。

源码级的读取与解码流程

读取方向的核心逻辑同样在 internal/action/binary.go 的binaryGet中,它被Cat和Sum(SHA256 校验和)两个命令共用:

sec, err := s.Store.Get(ctx, name) ... if !isBase64Encoded(sec) { // need to use sec.Bytes() otherwise the first line is missing. return sec.Bytes(), nil } body := sec.Body() buf, err := base64.StdEncoding.DecodeString(body)

解码前先做编码探测:isBase64Encoded(internal/action/binary.go)会同时检查Content-Transfer-Encoding与content-transfer-encoding两种大小写变体,只要任一值为base64就按 Base64 解码;否则回退为直接返回原始字节。这个兼容分支意味着gopass cat也能读取由insert等命令写入的普通文本条目(此时原样透传,不做解码)。

读取到解码字节后,Cat通过fmt.Fprint(stdout, string(buf))输出到 STDOUT;若条目不存在或解密失败,则返回Decrypt级别的错误(见 internal/action/binary.go)。命令入口经由 internal/action/handler_shims.go 的Action.Cat转发到binaryHandler.Cat。

与insert的区别

文档专门辟出一节说明与insert的差异:

In contrast toinsertit handles any kind of>

  • 应用安全
  • 开发工具

【免费下载链接】gopass

The slightly more awesome standard unix password manager for teams

项目地址:https://gitcode.com/gh_mirrors/go/gopass
点击查看免费下载
上一篇:surround-view-system-introduction架构解析:高性能实时图像处理系统设计
下一篇:Basic Computer Games 经典游戏移植指南:深入解析 NAME 游戏与多语言字符串处理实现

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表