Go 项目,包含: - 服务端 updater:两阶段协议,ECDSA 签名验证,AES-GCM 加密 - 发送端 dcu-send:Gitea Action CLI - internal/auth:加解密/签名/会话管理 - internal/docker:Docker CLI 容器查找/拉取/重建 - action/:Gitea Action 定义 - deploy/Dockerfile:多阶段构建 - .gitea/workflows/build.yaml:CI/CD
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// sessionEntry 存储一次 Phase 1 协商的会话密钥。
|
||||
type sessionEntry struct {
|
||||
key []byte // AES-256 会话密钥
|
||||
expiry time.Time
|
||||
}
|
||||
|
||||
// SessionManager 管理内存中的会话密钥(Nonce → AES Key)。
|
||||
// 每个 Phase 1 请求生成一个 session,Phase 2 消费后删除。
|
||||
type SessionManager struct {
|
||||
mu sync.Mutex
|
||||
store map[string]*sessionEntry
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
// NewSessionManager 创建会话密钥管理器。
|
||||
// ttl: 密钥过期时间(如 30 秒)
|
||||
func NewSessionManager(ttl time.Duration) *SessionManager {
|
||||
sm := &SessionManager{
|
||||
store: make(map[string]*sessionEntry),
|
||||
ttl: ttl,
|
||||
}
|
||||
// 后台协程定期清理过期密钥
|
||||
go sm.cleanupLoop()
|
||||
return sm
|
||||
}
|
||||
|
||||
// GenerateKey 生成 AES-256 会话密钥,用指定的 keyID 存储(通常用 nonce)。
|
||||
func (sm *SessionManager) GenerateKey(keyID string) ([]byte, error) {
|
||||
key := make([]byte, 32)
|
||||
if _, err := rand.Read(key); err != nil {
|
||||
return nil, fmt.Errorf("generate session key: %w", err)
|
||||
}
|
||||
|
||||
sm.mu.Lock()
|
||||
sm.store[keyID] = &sessionEntry{
|
||||
key: key,
|
||||
expiry: time.Now().Add(sm.ttl),
|
||||
}
|
||||
sm.mu.Unlock()
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// GetKey 获取并删除会话密钥(一次性使用)。
|
||||
// 返回 nil 表示 keyID 不存在或已过期。
|
||||
func (sm *SessionManager) GetKey(keyID string) []byte {
|
||||
sm.mu.Lock()
|
||||
defer sm.mu.Unlock()
|
||||
|
||||
entry, ok := sm.store[keyID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
delete(sm.store, keyID)
|
||||
|
||||
if time.Now().After(entry.expiry) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return entry.key
|
||||
}
|
||||
|
||||
// cleanupLoop 定期清理过期密钥。
|
||||
func (sm *SessionManager) cleanupLoop() {
|
||||
ticker := time.NewTicker(sm.ttl)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
sm.mu.Lock()
|
||||
now := time.Now()
|
||||
for id, entry := range sm.store {
|
||||
if now.After(entry.expiry) {
|
||||
delete(sm.store, id)
|
||||
}
|
||||
}
|
||||
sm.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// NonceCache 用于防重放攻击的 Nonce 缓存。
|
||||
type NonceCache struct {
|
||||
mu sync.Mutex
|
||||
store map[string]time.Time
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
// NewNonceCache 创建 Nonce 缓存。
|
||||
// ttl: Nonce 有效时间(如 60 秒)
|
||||
func NewNonceCache(ttl time.Duration) *NonceCache {
|
||||
nc := &NonceCache{
|
||||
store: make(map[string]time.Time),
|
||||
ttl: ttl,
|
||||
}
|
||||
go nc.cleanupLoop()
|
||||
return nc
|
||||
}
|
||||
|
||||
// Check 检查并记录 Nonce。返回 true 表示 Nonce 有效(未使用过)。
|
||||
// 返回 false 表示 Nonce 已存在(重放攻击)。
|
||||
func (nc *NonceCache) Check(nonce string) bool {
|
||||
nc.mu.Lock()
|
||||
defer nc.mu.Unlock()
|
||||
|
||||
if _, exists := nc.store[nonce]; exists {
|
||||
return false
|
||||
}
|
||||
|
||||
nc.store[nonce] = time.Now().Add(nc.ttl)
|
||||
return true
|
||||
}
|
||||
|
||||
func (nc *NonceCache) cleanupLoop() {
|
||||
ticker := time.NewTicker(nc.ttl)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
nc.mu.Lock()
|
||||
now := time.Now()
|
||||
for n, expiry := range nc.store {
|
||||
if now.After(expiry) {
|
||||
delete(nc.store, n)
|
||||
}
|
||||
}
|
||||
nc.mu.Unlock()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user