- Go gin 后端:流水线/节点/连线/运行/日志/GitOps/插件 REST API, SQLite(GORM) 自动建表 + seed,模拟执行引擎 + SSE 实时日志推送, 前端产物 go:embed 嵌入单二进制,一个端口同时服务 API 与页面 - React 19 前端:画布式流水线编辑器(React Flow + Tekton 任务库)、 GitOps 部署、批量发布、发布记录等 14 个模块页面, tRPC 全部替换为 REST(TanStack Query) - 首次启动生成随机密码管理员账号(日志 + data/initial-admin-password.txt) - run.sh 一键构建启动(默认端口 9527,支持 start/stop/restart/build/dev)
52 lines
1.5 KiB
Go
52 lines
1.5 KiB
Go
// Package crypto 提供口令哈希原语(argon2id,与 opsx-loki 同参数)。
|
|
package crypto
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/subtle"
|
|
"encoding/base64"
|
|
"math/big"
|
|
|
|
"golang.org/x/crypto/argon2"
|
|
)
|
|
|
|
// HashPassword 生成 argon2id 口令哈希(salt+hash base64 编码)
|
|
func HashPassword(password string) (string, error) {
|
|
salt := make([]byte, 16)
|
|
if _, err := rand.Read(salt); err != nil {
|
|
return "", err
|
|
}
|
|
hash := argon2.IDKey([]byte(password), salt, 3, 64*1024, 4, 32)
|
|
combined := append(salt, hash...)
|
|
return base64.StdEncoding.EncodeToString(combined), nil
|
|
}
|
|
|
|
// VerifyPassword 常数时间比对口令哈希
|
|
func VerifyPassword(password, hashStr string) bool {
|
|
combined, err := base64.StdEncoding.DecodeString(hashStr)
|
|
if err != nil || len(combined) < 16 {
|
|
return false
|
|
}
|
|
salt := combined[:16]
|
|
hash := combined[16:]
|
|
newHash := argon2.IDKey([]byte(password), salt, 3, 64*1024, 4, 32)
|
|
return subtle.ConstantTimeCompare(hash, newHash) == 1
|
|
}
|
|
|
|
// passwordAlphabet 去掉易混淆字符(0O1lI)的密码字母表
|
|
const passwordAlphabet = "23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ"
|
|
|
|
// RandomPassword 生成 n 位随机密码(crypto/rand,无易混淆字符)
|
|
func RandomPassword(n int) (string, error) {
|
|
max := big.NewInt(int64(len(passwordAlphabet)))
|
|
buf := make([]byte, n)
|
|
for i := range buf {
|
|
idx, err := rand.Int(rand.Reader, max)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
buf[i] = passwordAlphabet[idx.Int64()]
|
|
}
|
|
return string(buf), nil
|
|
}
|