Initial commit: docker-compose-updater
Build and Push / build (push) Failing after 13m20s

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:
ilovintit
2026-06-08 15:16:46 +08:00
commit cea9b941cf
21 changed files with 1874 additions and 0 deletions
+136
View File
@@ -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 请求生成一个 sessionPhase 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()
}
}