0d84b07f68
CI / docker (push) Successful in 1m58s
Go + Vue 管理台:Agent 隧道、域名反代、IP 安全、访客验证与监控大盘。 Gitea Actions CI 多架构镜像;纯 Go SQLite、无 CGO Docker 构建。 Co-authored-by: Cursor <cursoragent@cursor.com>
88 lines
1.9 KiB
Go
88 lines
1.9 KiB
Go
package store
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
func hashAPIKey(key string) string {
|
|
sum := sha256.Sum256([]byte(key))
|
|
return hex.EncodeToString(sum[:])
|
|
}
|
|
|
|
func generateAPIKeyPlain() (string, string, error) {
|
|
b := make([]byte, 24)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", "", err
|
|
}
|
|
plain := "wh_" + hex.EncodeToString(b)
|
|
prefix := plain
|
|
if len(prefix) > 12 {
|
|
prefix = prefix[:12]
|
|
}
|
|
return plain, prefix, nil
|
|
}
|
|
|
|
func (s *Store) ListAPIKeys(userID uint, isAdmin bool) ([]APIKey, error) {
|
|
var keys []APIKey
|
|
q := s.db.Order("id asc")
|
|
if !isAdmin {
|
|
q = q.Where("user_id = ?", userID)
|
|
}
|
|
return keys, q.Find(&keys).Error
|
|
}
|
|
|
|
func (s *Store) CreateAPIKey(name string, userID uint) (*APIKey, string, error) {
|
|
if name == "" {
|
|
return nil, "", errors.New("name required")
|
|
}
|
|
plain, prefix, err := generateAPIKeyPlain()
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
key := &APIKey{
|
|
Name: name,
|
|
KeyPrefix: prefix,
|
|
KeyHash: hashAPIKey(plain),
|
|
UserID: userID,
|
|
Status: true,
|
|
}
|
|
if err := s.db.Create(key).Error; err != nil {
|
|
return nil, "", err
|
|
}
|
|
return key, plain, nil
|
|
}
|
|
|
|
func (s *Store) DeleteAPIKey(id uint, userID uint, isAdmin bool) error {
|
|
var key APIKey
|
|
if err := s.db.First(&key, id).Error; err != nil {
|
|
return err
|
|
}
|
|
if !isAdmin && key.UserID != userID {
|
|
return fmt.Errorf("permission denied")
|
|
}
|
|
return s.db.Delete(&APIKey{}, id).Error
|
|
}
|
|
|
|
func (s *Store) ValidateAPIKey(plain string) (*User, error) {
|
|
if plain == "" {
|
|
return nil, errors.New("empty api key")
|
|
}
|
|
hash := hashAPIKey(plain)
|
|
var key APIKey
|
|
if err := s.db.Where("key_hash = ? AND status = ?", hash, true).First(&key).Error; err != nil {
|
|
return nil, errors.New("invalid api key")
|
|
}
|
|
user, err := s.GetUserByID(key.UserID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !user.Status {
|
|
return nil, errors.New("user disabled")
|
|
}
|
|
return user, nil
|
|
}
|