refactor: 改用 Cobra 命令行框架,reset-admin-password 带交互提示
- root.go 作为 Cobra 入口,DefaultRun 由 main 注入 serve() - reset_admin.go 改为 Cobra 子命令,支持 --user/--password 参数 - 交互式:多管理员时选择目标、密码支持手动输入或随机生成(term.ReadPassword 不回显) - 帮助输出自动生成,无需手写 Usage - 删除旧的 flag 实现
This commit is contained in:
@@ -0,0 +1,178 @@
|
|||||||
|
// Package cmd 命令行入口。
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/openteam/server/internal/config"
|
||||||
|
"github.com/openteam/server/internal/pkg/crypto"
|
||||||
|
"github.com/openteam/server/internal/store"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/term"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// pwAlphabet 密码随机串字符集(去掉 0/O/1/l/I 等易混淆字符)。
|
||||||
|
const pwAlphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz"
|
||||||
|
|
||||||
|
var (
|
||||||
|
resetUser string
|
||||||
|
resetPassword string
|
||||||
|
)
|
||||||
|
|
||||||
|
var resetAdminPasswordCmd = &cobra.Command{
|
||||||
|
Use: "reset-admin-password",
|
||||||
|
Short: "重置管理员密码",
|
||||||
|
Long: `重置管理员密码(忘记密码时用,需在可加载配置的目录下执行)。
|
||||||
|
|
||||||
|
交互式引导(默认):
|
||||||
|
go run ./cmd/server reset-admin-password
|
||||||
|
|
||||||
|
非交互式(用于脚本):
|
||||||
|
go run ./cmd/server reset-admin-password --user admin --password "新密码"`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
runResetAdminPassword()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(resetAdminPasswordCmd)
|
||||||
|
resetAdminPasswordCmd.Flags().StringVar(&resetUser, "user", "", "目标管理员用户名(留空则交互选择)")
|
||||||
|
resetAdminPasswordCmd.Flags().StringVar(&resetPassword, "password", "", "新密码,至少 8 位(留空则交互输入)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func runResetAdminPassword() {
|
||||||
|
// --- 阶段 1:加载配置与数据库 ---
|
||||||
|
cfg, err := config.Load()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("加载配置失败: %v", err)
|
||||||
|
}
|
||||||
|
db, err := store.Open(cfg.DB.Driver, cfg.DB.DSN)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("连接数据库失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 阶段 2:列出管理员 ---
|
||||||
|
var admins []struct {
|
||||||
|
ID uint64
|
||||||
|
Username string
|
||||||
|
}
|
||||||
|
db.Model(&store.User{}).Select("id, username").Where("role = ?", store.RoleAdmin).Find(&admins)
|
||||||
|
if len(admins) == 0 {
|
||||||
|
log.Fatalf("系统中没有管理员用户")
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 阶段 3:选择目标管理员 ---
|
||||||
|
target := targetAdmin(db, admins)
|
||||||
|
|
||||||
|
// --- 阶段 4:获取新密码 ---
|
||||||
|
var pw string
|
||||||
|
if resetPassword != "" {
|
||||||
|
pw = resetPassword
|
||||||
|
} else {
|
||||||
|
pw = promptPassword()
|
||||||
|
}
|
||||||
|
if pw == "" {
|
||||||
|
log.Fatalf("密码不能为空")
|
||||||
|
}
|
||||||
|
if len(pw) < 8 || len(pw) > 72 {
|
||||||
|
log.Fatalf("密码长度必须在 8 到 72 位之间")
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 阶段 5:加密并更新 ---
|
||||||
|
hasher := crypto.NewPasswordHasher(cfg.Auth.Argon2Time, cfg.Auth.Argon2Memory, cfg.Auth.Argon2Threads, cfg.Auth.Argon2KeyLen, cfg.Auth.SaltLen)
|
||||||
|
hash, err := hasher.HashPassword(pw)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("加密密码失败: %v", err)
|
||||||
|
}
|
||||||
|
if err := db.Model(&store.User{}).Where("id = ?", target.ID).Update("password_hash", hash).Error; err != nil {
|
||||||
|
log.Fatalf("更新密码失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("✅ 已重置管理员 %q 的密码!\n", target.Username)
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetAdmin 解析 --user 或交互选择目标管理员。
|
||||||
|
func targetAdmin(db *gorm.DB, admins []struct {
|
||||||
|
ID uint64
|
||||||
|
Username string
|
||||||
|
}) *store.User {
|
||||||
|
if resetUser != "" {
|
||||||
|
for i := range admins {
|
||||||
|
if admins[i].Username == resetUser {
|
||||||
|
return &store.User{ID: admins[i].ID, Username: admins[i].Username}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Fatalf("管理员 %q 不存在", resetUser)
|
||||||
|
}
|
||||||
|
if len(admins) == 1 {
|
||||||
|
return &store.User{ID: admins[0].ID, Username: admins[0].Username}
|
||||||
|
}
|
||||||
|
return selectAdmin(admins)
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectAdmin 交互式选择管理员用户。
|
||||||
|
func selectAdmin(admins []struct {
|
||||||
|
ID uint64
|
||||||
|
Username string
|
||||||
|
}) *store.User {
|
||||||
|
fmt.Println("检测到多个管理员用户,请选择要重置密码的目标:")
|
||||||
|
for i, a := range admins {
|
||||||
|
fmt.Printf(" [%d] %s\n", i+1, a.Username)
|
||||||
|
}
|
||||||
|
fmt.Printf("请输入编号 (1-%d): ", len(admins))
|
||||||
|
var n int
|
||||||
|
if _, err := fmt.Scanf("%d", &n); err != nil || n < 1 || n > len(admins) {
|
||||||
|
log.Fatalf("无效输入")
|
||||||
|
}
|
||||||
|
return &store.User{ID: admins[n-1].ID, Username: admins[n-1].Username}
|
||||||
|
}
|
||||||
|
|
||||||
|
// promptPassword 交互式输入密码,并提供两种方式选择。
|
||||||
|
func promptPassword() string {
|
||||||
|
fmt.Println("请选择密码设置方式:")
|
||||||
|
fmt.Println(" [1] 手动输入密码")
|
||||||
|
fmt.Println(" [2] 自动生成随机密码(16 位,不含易混淆字符)")
|
||||||
|
fmt.Printf("请输入编号 (1-2): ")
|
||||||
|
|
||||||
|
var n int
|
||||||
|
if _, err := fmt.Scanf("%d", &n); err != nil || n < 1 || n > 2 {
|
||||||
|
log.Fatalf("无效输入,请输入 1 或 2")
|
||||||
|
}
|
||||||
|
if n == 2 {
|
||||||
|
pw, err := randomPassword(16)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("生成随机密码失败: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("🔑 生成的随机密码:%s\n", pw)
|
||||||
|
fmt.Println("(请立即保存,不会再次显示)")
|
||||||
|
return pw
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动输入:静默输入(不回显)
|
||||||
|
fmt.Print("请输入新密码(至少 8 位):")
|
||||||
|
raw, err := term.ReadPassword(int(os.Stdin.Fd()))
|
||||||
|
fmt.Println()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("读取密码失败: %v", err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(raw))
|
||||||
|
}
|
||||||
|
|
||||||
|
// randomPassword 用 crypto/rand 从 pwAlphabet 生成 n 位随机密码。
|
||||||
|
func randomPassword(n int) (string, error) {
|
||||||
|
buf := make([]byte, n)
|
||||||
|
for i := range buf {
|
||||||
|
k, err := rand.Int(rand.Reader, big.NewInt(int64(len(pwAlphabet))))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
buf[i] = pwAlphabet[k.Int64()]
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// Package cmd 命令行入口(Cobra 子命令分发)。
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultRun 无子命令时的默认行为(由 main 注入服务启动函数)。
|
||||||
|
var DefaultRun func()
|
||||||
|
|
||||||
|
// Execute 启动根命令。
|
||||||
|
func Execute() {
|
||||||
|
cobra.CheckErr(rootCmd.Execute())
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "openteam",
|
||||||
|
Short: "openteam · LLM API 中转站",
|
||||||
|
Long: `openteam 大模型中转站 API 服务。
|
||||||
|
|
||||||
|
直接运行(无子命令)启动 HTTP 服务:
|
||||||
|
go run ./cmd/server
|
||||||
|
|
||||||
|
子命令:
|
||||||
|
reset-admin-password 重置管理员密码(交互式,无参数时自动提示)`,
|
||||||
|
Run: func(c *cobra.Command, args []string) {
|
||||||
|
if DefaultRun != nil {
|
||||||
|
DefaultRun()
|
||||||
|
} else {
|
||||||
|
_ = c.Help()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -13,19 +13,22 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/openteam/server/cmd/server/cmd"
|
||||||
"github.com/openteam/server/internal/api"
|
"github.com/openteam/server/internal/api"
|
||||||
"github.com/openteam/server/internal/app"
|
"github.com/openteam/server/internal/app"
|
||||||
"github.com/openteam/server/internal/config"
|
"github.com/openteam/server/internal/config"
|
||||||
"github.com/openteam/server/internal/proxy"
|
"github.com/openteam/server/internal/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func init() {
|
||||||
// 子命令分发:`openteam reset-admin-password ...`(无子命令时启动服务)
|
cmd.DefaultRun = serve
|
||||||
if len(os.Args) > 1 && os.Args[1] == "reset-admin-password" {
|
}
|
||||||
runResetAdminPassword(os.Args[2:])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func serve() {
|
||||||
cfg, err := config.Load()
|
cfg, err := config.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("config: %v", err)
|
log.Fatalf("config: %v", err)
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
// 子命令 reset-admin-password:重置管理员密码(忘记密码时用,需在 server/ 目录或配置可加载处执行)。
|
|
||||||
// 用法:go run ./cmd/server reset-admin-password [-user admin] [-password 新密码]
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/openteam/server/internal/config"
|
|
||||||
"github.com/openteam/server/internal/pkg/crypto"
|
|
||||||
"github.com/openteam/server/internal/store"
|
|
||||||
)
|
|
||||||
|
|
||||||
// pwAlphabet 密码随机串字符集(去掉 0/O/1/l/I 等易混淆字符)。
|
|
||||||
const pwAlphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz"
|
|
||||||
|
|
||||||
func runResetAdminPassword(args []string) {
|
|
||||||
fs := flag.NewFlagSet("reset-admin-password", flag.ExitOnError)
|
|
||||||
user := fs.String("user", "admin", "目标管理员用户名")
|
|
||||||
password := fs.String("password", "", "新密码(至少 8 位;留空则随机生成并打印一次)")
|
|
||||||
_ = fs.Parse(args)
|
|
||||||
|
|
||||||
cfg, err := config.Load()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("config: %v", err)
|
|
||||||
}
|
|
||||||
db, err := store.Open(cfg.DB.Driver, cfg.DB.DSN)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("db: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var u store.User
|
|
||||||
if err := db.Where("username = ? AND role = ?", *user, store.RoleAdmin).First(&u).Error; err != nil {
|
|
||||||
log.Fatalf("admin user %q not found", *user)
|
|
||||||
}
|
|
||||||
|
|
||||||
pw := *password
|
|
||||||
generated := false
|
|
||||||
if pw == "" {
|
|
||||||
pw, err = randomPassword(16)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("generate password: %v", err)
|
|
||||||
}
|
|
||||||
generated = true
|
|
||||||
}
|
|
||||||
if len(pw) < 8 || len(pw) > 72 {
|
|
||||||
log.Fatal("password length must be between 8 and 72")
|
|
||||||
}
|
|
||||||
|
|
||||||
hasher := crypto.NewPasswordHasher(cfg.Auth.Argon2Time, cfg.Auth.Argon2Memory, cfg.Auth.Argon2Threads, cfg.Auth.Argon2KeyLen, cfg.Auth.SaltLen)
|
|
||||||
hash, err := hasher.HashPassword(pw)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("hash password: %v", err)
|
|
||||||
}
|
|
||||||
if err := db.Model(&store.User{}).Where("id = ?", u.ID).Update("password_hash", hash).Error; err != nil {
|
|
||||||
log.Fatalf("update password: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if generated {
|
|
||||||
fmt.Printf("已重置 %q 的密码:%s\n", u.Username, pw)
|
|
||||||
fmt.Println("(请立即保存,不会再次显示)")
|
|
||||||
} else {
|
|
||||||
fmt.Printf("已重置 %q 的密码。\n", u.Username)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// randomPassword 用 crypto/rand 从 pwAlphabet 生成 n 位随机密码。
|
|
||||||
func randomPassword(n int) (string, error) {
|
|
||||||
buf := make([]byte, n)
|
|
||||||
for i := range buf {
|
|
||||||
k, err := rand.Int(rand.Reader, big.NewInt(int64(len(pwAlphabet))))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
buf[i] = pwAlphabet[k.Int64()]
|
|
||||||
}
|
|
||||||
return string(buf), nil
|
|
||||||
}
|
|
||||||
@@ -7,9 +7,11 @@ require (
|
|||||||
github.com/glebarez/sqlite v1.11.0
|
github.com/glebarez/sqlite v1.11.0
|
||||||
github.com/go-webauthn/webauthn v0.17.4
|
github.com/go-webauthn/webauthn v0.17.4
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||||
|
github.com/spf13/cobra v1.10.2
|
||||||
github.com/spf13/viper v1.21.0
|
github.com/spf13/viper v1.21.0
|
||||||
github.com/tiktoken-go/tokenizer v0.8.1
|
github.com/tiktoken-go/tokenizer v0.8.1
|
||||||
golang.org/x/crypto v0.55.0
|
golang.org/x/crypto v0.55.0
|
||||||
|
golang.org/x/term v0.45.0
|
||||||
gorm.io/driver/postgres v1.6.2
|
gorm.io/driver/postgres v1.6.2
|
||||||
gorm.io/gorm v1.31.2
|
gorm.io/gorm v1.31.2
|
||||||
)
|
)
|
||||||
@@ -35,6 +37,7 @@ require (
|
|||||||
github.com/goccy/go-yaml v1.19.2 // indirect
|
github.com/goccy/go-yaml v1.19.2 // indirect
|
||||||
github.com/google/go-tpm v0.9.8 // indirect
|
github.com/google/go-tpm v0.9.8 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
github.com/jackc/pgx/v5 v5.10.0 // indirect
|
github.com/jackc/pgx/v5 v5.10.0 // indirect
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiD
|
|||||||
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -60,6 +61,8 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbu
|
|||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
@@ -106,6 +109,7 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
|
|||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||||
@@ -114,6 +118,9 @@ github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
|||||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
|
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||||
|
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||||
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||||
@@ -159,6 +166,8 @@ golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
|||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
|
||||||
|
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
|
||||||
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
|
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
|
||||||
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
|
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
|
||||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||||
|
|||||||
Reference in New Issue
Block a user