chore: 统一本地服务器与远程仓库源码
- 合并 main 与 master 历史并以服务器结构为基线 - 保留迁移、数据保留、AWS 账单与部署安全能力 - 建立 SDD 规格和 CI 验证闭环
This commit is contained in:
commit
fd60361d93
460 files changed
+37492
-23871
No files matched your search
@@ -0,0 +1,81 @@
|
||||
package agentauth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ezops/model"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Issue 为指定主机轮换 Agent Token,旧 Token 会立即失效。 // Logan.Li
|
||||
func Issue(db *gorm.DB, hostname, issuedBy string) (string, error) {
|
||||
hostname = strings.TrimSpace(hostname)
|
||||
if hostname == "" {
|
||||
return "", fmt.Errorf("hostname is required")
|
||||
}
|
||||
prefix, err := randomHex(8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// bcrypt 只处理前 72 字节,Token 总长度控制在 61 字节以内。 // Logan.Li
|
||||
secret, err := randomHex(20)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
token := "agt_" + prefix + "." + secret
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(token), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
now := time.Now()
|
||||
credential := model.AgentCredential{Hostname: hostname}
|
||||
err = db.Where("hostname = ?", hostname).Assign(map[string]interface{}{
|
||||
"token_prefix": "agt_" + prefix,
|
||||
"token_hash": string(hash),
|
||||
"status": "active",
|
||||
"issued_by": issuedBy,
|
||||
"last_used_at": nil,
|
||||
"expires_at": nil,
|
||||
"rotated_at": now,
|
||||
}).FirstOrCreate(&credential).Error
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// Authenticate 校验 Token 并返回绑定的主机名。 // Logan.Li
|
||||
func Authenticate(db *gorm.DB, token string) (*model.AgentCredential, error) {
|
||||
parts := strings.SplitN(token, ".", 2)
|
||||
if len(parts) != 2 || !strings.HasPrefix(parts[0], "agt_") || parts[1] == "" {
|
||||
return nil, fmt.Errorf("invalid agent token")
|
||||
}
|
||||
var credential model.AgentCredential
|
||||
if err := db.Where("token_prefix = ? AND status = ?", parts[0], "active").Take(&credential).Error; err != nil {
|
||||
return nil, fmt.Errorf("invalid agent token")
|
||||
}
|
||||
if credential.ExpiresAt != nil && credential.ExpiresAt.Before(time.Now()) {
|
||||
return nil, fmt.Errorf("agent token expired")
|
||||
}
|
||||
if bcrypt.CompareHashAndPassword([]byte(credential.TokenHash), []byte(token)) != nil {
|
||||
return nil, fmt.Errorf("invalid agent token")
|
||||
}
|
||||
now := time.Now()
|
||||
_ = db.Model(&credential).Update("last_used_at", now).Error
|
||||
credential.LastUsedAt = &now
|
||||
return &credential, nil
|
||||
}
|
||||
|
||||
func randomHex(bytes int) (string, error) {
|
||||
buf := make([]byte, bytes)
|
||||
if _, err := rand.Read(buf); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(buf), nil
|
||||
}
|
||||
Reference in new issue
Block a user