今天我们用 OpenCode 做一个命令行随机密码生成器。输入一条指令,它就能生成指定长度、指定强度的随机密码,支持排除易混淆字符(如 i/1/l),还能批量生成并显示密码熵值——让你一眼看出密码够不够安全。
确保本地已安装 Go(1.18+),然后打开终端进入工作目录。在 VS Code / Cursor / 任意终端中启动 OpenCode:
opencode
进入交互模式后,直接开始对话。
我对 OpenCode 说的第一句话:
> "用 Go 写一个命令行随机密码生成器。支持 -l 指定长度、-n 指定生成数量,使用 crypto/rand 保证密码学安全,不要任何外部依赖。"
OpenCode 直接生成了 main.go,包含 flag 参数解析和 crypto/rand 随机生成逻辑。核心生成函数长这样:
func generate(length int, charset string) (string, error) {
var builder strings.Builder
charsLen := len(charset)
for i := 0; i < length; i++ {
n, err := rand.Int(rand.Reader, big.NewInt(int64(charsLen)))
if err != nil {
return "", err
}
builder.WriteByte(charset[n.Int64()])
}
return builder.String(), nil
}
关键点:用 crypto/rand 而非 math/rand,因为 crypto/rand 从操作系统熵源读取,适合生成密码。math/rand 是伪随机,不适合安全场景。
默认字符集中有些字符肉眼难以分辨——i 和 1、l 和 I、o 和 0、O 和 0。我对 OpenCode 说:
> "加一个 --no-ambiguous 选项,排除 il1Lo0O 这些易混淆字符。同时加上 --no-upper、--no-digit、--no-symbol 选项让用户自定义字符集。"
OpenCode 新增了 removeAmbiguous 函数和 buildCharset 构造逻辑:
const ambiguous = "il1Lo0O"
func removeAmbiguous(s string) string {
var result strings.Builder
for _, c := range s {
if !strings.ContainsRune(ambiguous, c) {
result.WriteRune(c)
}
}
return result.String()
}
这里我注意到了 OpenCode 的一个好习惯:它把字符集构造单独抽成 buildCharset 函数,而不是把所有逻辑堆在 main 里。即使是很小的项目,它也保持了良好的代码结构。
密码安不安全,光看长度不够,关键看"熵"——组合可能性的数学度量。我说:
> "再加个密码熵值显示。非静默模式下输出 [强]/[中]/[弱] 标签和具体 bits 数。80 bits 以上算强,60-80 算中等,60 以下算弱。"
OpenCode 在打印逻辑中加入熵计算:
entropy := float64(*length) * math.Log2(float64(len(charset)))
if entropy >= 80 {
fmt.Print("[强] ")
} else if entropy >= 60 {
fmt.Print("[中] ")
} else {
fmt.Print("[弱] ")
}
fmt.Printf("(%.0f bits) ", entropy)
同时加上了 -q 静默模式,方便在脚本中直接用 $(passgen -q) 取值。
我对 OpenCode 说:
> "帮我初始化 Go module,编译并跑几个测试用例。"
OpenCode 执行了:
go mod init passgen go build -o passgen . ./passgen -n 3 -l 20
输出结果:
[1] [强] (129 bits) bVx_nahS%#5Cif,OJT38 [2] [强] (129 bits) $e%Z@+p_XL0*=K3aO]4@ [3] [强] (129 bits) a0)4d%!BTXU@5LU$EF%$
20 位密码,字符集 87 个字符,熵值 129 bits——远超 80 bits 的安全基线。
再测试短密码和弱字符集:
./passgen -l 6 --no-upper --no-digit --no-symbol # [弱] (28 bits) thhiys
只用 6 位小写字母,熵值仅 28 bits,立刻暴露出密码不安全。
总共从写下第一句提示词到拿到可运行的二进制文件,大约 4 分钟。
package main
import (
"crypto/rand"
"flag"
"fmt"
"math"
"math/big"
"strings"
)
const (
lowercase = "abcdefghijklmnopqrstuvwxyz"
uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
digits = "0123456789"
symbols = "!@#$%^&*()-_=+[]{}|;:,.<>?"
ambiguous = "il1Lo0O"
)
func main() {
length := flag.Int("l", 16, "密码长度")
noUpper := flag.Bool("no-upper", false, "排除大写字母")
noDigit := flag.Bool("no-digit", false, "排除数字")
noSymbol := flag.Bool("no-symbol", false, "排除特殊符号")
noAmbig := flag.Bool("no-ambiguous", false, "排除易混淆字符")
count := flag.Int("n", 1, "生成数量")
quiet := flag.Bool("q", false, "静默模式,只输出密码")
flag.Parse()
charset := buildCharset(*noUpper, *noDigit, *noSymbol, *noAmbig)
for i := 0; i < *count; i++ {
pass, err := generate(*length, charset)
if err != nil {
fmt.Fprintf(flag.CommandLine.Output(), "生成失败: %v\n", err)
return
}
if !*quiet && *count > 1 {
fmt.Printf("[%d] ", i+1)
}
if !*quiet {
entropy := float64(*length) * math.Log2(float64(len(charset)))
if entropy >= 80 {
fmt.Print("[强] ")
} else if entropy >= 60 {
fmt.Print("[中] ")
} else {
fmt.Print("[弱] ")
}
fmt.Printf("(%.0f bits) ", entropy)
}
fmt.Println(pass)
}
}
func buildCharset(noUpper, noDigit, noSymbol, noAmbig bool) string {
charset := lowercase
if !noUpper {
charset += uppercase
}
if !noDigit {
charset += digits
}
if !noSymbol {
charset += symbols
}
if noAmbig {
charset = removeAmbiguous(charset)
}
return charset
}
func removeAmbiguous(s string) string {
var result strings.Builder
for _, c := range s {
if !strings.ContainsRune(ambiguous, c) {
result.WriteRune(c)
}
}
return result.String()
}
func generate(length int, charset string) (string, error) {
var builder strings.Builder
charsLen := len(charset)
for i := 0; i < length; i++ {
n, err := rand.Int(rand.Reader, big.NewInt(int64(charsLen)))
if err != nil {
return "", err
}
builder.WriteByte(charset[n.Int64()])
}
return builder.String(), nil
}
这个项目的完整开发过程不到 4 分钟——从描述需求到拿到可用的二进制文件。整个过程我没有写一行 Go 代码,全部通过自然语言对话完成。
与传统开发方式的对比:
| 环节 | 手动开发 | 用 OpenCode |
|------|---------|------------|
| 参数解析 | 查 flag 文档、手写 | 一句话描述需求 |
| crypto/rand | 查文档确认 API | 自动选用正确库 |
| 熵值计算 | 查公式、手写 math.Log2 | 直接说"显示熵值" |
| 编译测试 | 手动 go build | OpenCode 一步执行 |
核心体会是:OpenCode 不是帮你"写代码",而是帮你"做项目"。你只需要描述你想要什么,它负责从代码编写到编译测试的全流程。这种体验对于 Prototype 阶段的小工具开发效率提升非常明显。
你可以把 passgen 安装到系统路径中日常使用:
go build -o passgen . && sudo mv passgen /usr/local/bin/
下次再也不用在网页上点"生成密码"了,终端里敲一行搞定。