refactor(plugin): 简化插件签名验证机制
Some checks failed
Build Multi-Platform Binaries / build-frontend (push) Failing after 13m34s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Has been cancelled

- 移除远程密钥撤销检查功能
- 移除远程公钥列表拉取和缓存机制
- 将官方公钥改为客户端内置固定值
- 简化 GetPublicKeyByID 接口实现
- 移除相关的安全配置初始化代码
- 将插件仓库URL配置改为可配置化设置
This commit is contained in:
Flik
2025-12-31 21:29:16 +08:00
parent 42e11e0aca
commit 07c8f18761
7 changed files with 25 additions and 546 deletions

View File

@@ -2,217 +2,30 @@ package sign
import (
"crypto/ed25519"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"sync"
"time"
)
// KeyEntry 密钥条目
type KeyEntry struct {
ID string `json:"id"`
PublicKey string `json:"public_key"`
ValidFrom time.Time `json:"valid_from"`
RevokedAt time.Time `json:"revoked_at,omitempty"`
}
// 官方公钥列表(支持密钥轮换)
var officialKeys = []KeyEntry{
{
ID: "official-v1",
PublicKey: "0A0xRthj0wgPg8X8GJZ6/EnNpAUw5v7O//XLty+P5Yw=",
ValidFrom: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC),
},
// 添加新密钥时,在此处追加
}
// 官方固定公钥(客户端内置)
const OfficialPublicKeyBase64 = "0A0xRthj0wgPg8X8GJZ6/EnNpAUw5v7O//XLty+P5Yw="
var (
keyCache map[string]ed25519.PublicKey
keyCacheOnce sync.Once
keyMu sync.RWMutex
remoteKeys []KeyEntry
officialPubKey ed25519.PublicKey
officialPubKeyOnce sync.Once
officialPubKeyErr error
)
// KeyListConfig 远程公钥列表配置
type KeyListConfig struct {
RemoteURL string
FetchInterval time.Duration
RequestTimeout time.Duration
// initOfficialKey 初始化官方公钥
func initOfficialKey() {
officialPubKey, officialPubKeyErr = DecodePublicKey(OfficialPublicKeyBase64)
}
var keyListConfig = KeyListConfig{
RemoteURL: "",
FetchInterval: 24 * time.Hour,
RequestTimeout: 10 * time.Second,
}
// SetKeyListConfig 设置远程公钥列表配置
func SetKeyListConfig(cfg KeyListConfig) {
keyMu.Lock()
defer keyMu.Unlock()
keyListConfig = cfg
}
// initKeyCache 初始化密钥缓存
func initKeyCache() {
keyCache = make(map[string]ed25519.PublicKey)
for _, entry := range officialKeys {
if pub, err := DecodePublicKey(entry.PublicKey); err == nil {
keyCache[entry.ID] = pub
}
}
}
// GetOfficialPublicKey 获取默认官方公钥(兼容旧接口)
// GetOfficialPublicKey 获取官方公钥
func GetOfficialPublicKey() (ed25519.PublicKey, error) {
return GetPublicKeyByID("official-v1")
officialPubKeyOnce.Do(initOfficialKey)
return officialPubKey, officialPubKeyErr
}
// GetPublicKeyByID 根据 ID 获取公钥
// GetPublicKeyByID 根据 ID 获取公钥(兼容旧接口,忽略 keyID
func GetPublicKeyByID(keyID string) (ed25519.PublicKey, error) {
keyCacheOnce.Do(initKeyCache)
keyMu.RLock()
pub, ok := keyCache[keyID]
keyMu.RUnlock()
if !ok {
return nil, fmt.Errorf("unknown key ID: %s", keyID)
}
return pub, nil
}
// IsKeyRevoked 检查密钥是否已吊销
func IsKeyRevoked(keyID string) bool {
// 先检查内置密钥
for _, entry := range officialKeys {
if entry.ID == keyID {
return !entry.RevokedAt.IsZero()
}
}
// 再检查远程密钥
keyMu.RLock()
defer keyMu.RUnlock()
for _, entry := range remoteKeys {
if entry.ID == keyID {
return !entry.RevokedAt.IsZero()
}
}
return true // 未知密钥视为已吊销
}
// GetKeyEntry 获取密钥条目
func GetKeyEntry(keyID string) *KeyEntry {
for i := range officialKeys {
if officialKeys[i].ID == keyID {
return &officialKeys[i]
}
}
keyMu.RLock()
defer keyMu.RUnlock()
for i := range remoteKeys {
if remoteKeys[i].ID == keyID {
return &remoteKeys[i]
}
}
return nil
}
// KeyList 远程公钥列表结构
type KeyList struct {
Version int `json:"version"`
UpdatedAt int64 `json:"updated_at"`
Keys []KeyEntry `json:"keys"`
Signature string `json:"signature"`
}
// FetchRemoteKeyList 从远程拉取公钥列表
func FetchRemoteKeyList() error {
keyMu.RLock()
cfg := keyListConfig
keyMu.RUnlock()
if cfg.RemoteURL == "" {
return nil
}
client := &http.Client{Timeout: cfg.RequestTimeout}
resp, err := client.Get(cfg.RemoteURL)
if err != nil {
return fmt.Errorf("fetch key list: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("fetch key list: status %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read key list: %w", err)
}
var list KeyList
if err := json.Unmarshal(body, &list); err != nil {
return fmt.Errorf("parse key list: %w", err)
}
// 验证签名(使用内置公钥验证)
if err := verifyKeyListSignature(&list); err != nil {
return fmt.Errorf("verify key list: %w", err)
}
return updateKeyCache(&list)
}
// verifyKeyListSignature 验证公钥列表签名
func verifyKeyListSignature(list *KeyList) error {
if list.Signature == "" {
return fmt.Errorf("missing signature")
}
// 使用内置公钥验证(必须用内置密钥签名)
pubKey, err := GetOfficialPublicKey()
if err != nil {
return err
}
signData := struct {
Version int `json:"version"`
UpdatedAt int64 `json:"updated_at"`
Keys []KeyEntry `json:"keys"`
}{
Version: list.Version,
UpdatedAt: list.UpdatedAt,
Keys: list.Keys,
}
data, err := json.Marshal(signData)
if err != nil {
return err
}
return VerifyBase64(pubKey, data, list.Signature)
}
// updateKeyCache 更新公钥缓存
func updateKeyCache(list *KeyList) error {
keyMu.Lock()
defer keyMu.Unlock()
// 保存远程密钥列表
remoteKeys = list.Keys
// 更新缓存
for _, entry := range list.Keys {
if pub, err := DecodePublicKey(entry.PublicKey); err == nil {
keyCache[entry.ID] = pub
}
}
log.Printf("[KeyList] Updated with %d keys", len(list.Keys))
return nil
return GetOfficialPublicKey()
}