92 lines
2.1 KiB
Go
92 lines
2.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"fmt"
|
|
"ghproxy/config"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/go-json-experiment/json"
|
|
)
|
|
|
|
type Blacklist struct {
|
|
userSet map[string]struct{} // 用户级黑名单
|
|
repoSet map[string]map[string]struct{} // 仓库级黑名单
|
|
initOnce sync.Once // 确保初始化只执行一次
|
|
initialized bool // 初始化状态标识
|
|
}
|
|
|
|
var (
|
|
instance *Blacklist
|
|
initErr error
|
|
)
|
|
|
|
// InitBlacklist 初始化黑名单(线程安全,仅执行一次)
|
|
func InitBlacklist(cfg *config.Config) error {
|
|
instance = &Blacklist{
|
|
userSet: make(map[string]struct{}),
|
|
repoSet: make(map[string]map[string]struct{}),
|
|
}
|
|
|
|
data, err := os.ReadFile(cfg.Blacklist.BlacklistFile)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read blacklist: %w", err)
|
|
}
|
|
|
|
var list struct {
|
|
Entries []string `json:"blacklist"`
|
|
}
|
|
if err := json.Unmarshal(data, &list); err != nil {
|
|
return fmt.Errorf("invalid blacklist format: %w", err)
|
|
}
|
|
|
|
for _, entry := range list.Entries {
|
|
user, repo := splitUserRepo(entry)
|
|
switch {
|
|
case repo == "" || repo == "*":
|
|
instance.userSet[user] = struct{}{}
|
|
default:
|
|
if _, exists := instance.repoSet[user]; !exists {
|
|
instance.repoSet[user] = make(map[string]struct{})
|
|
}
|
|
instance.repoSet[user][repo] = struct{}{}
|
|
}
|
|
}
|
|
|
|
instance.initialized = true
|
|
return nil
|
|
}
|
|
|
|
// CheckBlacklist 检查用户和仓库是否在黑名单中(无锁设计)
|
|
func CheckBlacklist(username, repo string) bool {
|
|
if instance == nil || !instance.initialized {
|
|
return false
|
|
}
|
|
|
|
// 先检查用户级黑名单
|
|
if _, exists := instance.userSet[username]; exists {
|
|
return true
|
|
}
|
|
|
|
// 再检查仓库级黑名单
|
|
if repos, userExists := instance.repoSet[username]; userExists {
|
|
// 允许仓库名为空时的全用户仓库匹配
|
|
if repo == "" {
|
|
return true
|
|
}
|
|
_, repoExists := repos[repo]
|
|
return repoExists
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// splitUserRepo 优化分割逻辑(仅初始化时使用)
|
|
func splitUserRepo(fullRepo string) (user, repo string) {
|
|
if idx := strings.Index(fullRepo, "/"); idx > 0 {
|
|
return fullRepo[:idx], fullRepo[idx+1:]
|
|
}
|
|
return fullRepo, ""
|
|
}
|