1
0
mirror of https://github.com/fumiama/go-onebot-agent.git synced 2026-06-05 02:00:23 +08:00
Files
go-onebot-agent/perm.go
2025-09-25 23:02:09 +08:00

127 lines
2.7 KiB
Go

package goba
import (
_ "embed"
"os"
"strings"
"github.com/RomiChan/syncx"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)
var (
// ErrNoSuchPermRole role 不在 config 记录中
ErrNoSuchPermRole = errors.New("no such perm role")
// ErrUnexpectedAction 该 action 在 config 中找到但在 actions 中不存在
ErrUnexpectedAction = errors.New("unexpected action")
)
// PermRole 和 yaml config 一一对应
type PermRole string
const (
// PermRoleOwner 群主或主人
PermRoleOwner PermRole = "owner"
// PermRoleAdmin 管理
PermRoleAdmin PermRole = "admin"
// PermRoleUser 普通用户
PermRoleUser PermRole = "user"
)
//go:embed actions.yaml
var innerpermtable []byte
// PermAction 记录 action 的描述和 params
type PermAction struct {
Desc string `yaml:"desc"`
Params string `yaml:"params"`
Data string `yaml:"data"`
}
// Perm 即 actions.yaml 的 Go struct 映射
type Perm struct {
Actions map[string]PermAction `yaml:"actions"`
Config map[PermRole][]string `yaml:"config"`
cache syncx.Map[PermRole, actions] `yaml:"-"`
}
func (p *Perm) mdtable(role PermRole) (string, error) {
acs, ok := p.Config[role]
if !ok {
return "", errors.Wrap(ErrNoSuchPermRole, string(role))
}
table := strings.Builder{}
table.WriteString("|功能|action|params|data|\n|---|---|---|---|")
var ac actions
if _, ok := p.cache.Load(role); ok {
ac = actions{}
}
for _, act := range acs {
a, ok := p.Actions[act]
if !ok {
panic(errors.Wrap(ErrUnexpectedAction, act))
}
if ac != nil {
ac[act] = struct{}{}
}
table.WriteString("\n|")
table.WriteString(a.Desc)
table.WriteByte('|')
table.WriteString(act)
table.WriteByte('|')
table.WriteString(a.Params)
table.WriteByte('|')
table.WriteString(a.Data)
table.WriteByte('|')
}
if ac != nil {
p.cache.Store(role, ac)
}
return table.String(), nil
}
func (p *Perm) allow(role PermRole, action string) bool {
ac, ok := p.cache.Load(role)
if ok {
return ac.allow(action)
}
acs, ok := p.Config[role]
if !ok {
return false
}
ac = actions{}
for _, act := range acs {
ac[act] = struct{}{}
}
p.cache.Store(role, ac)
return ac.allow(action)
}
type actions map[string]struct{}
func (ac actions) allow(action string) bool {
_, ok := ac[action]
return ok
}
// LoadPermTable 读取 yaml file 并根据权限生成 MD 表格, 参数为空则加载内嵌配置
func (ag *Agent) LoadPermTable(file ...string) error {
var data []byte
if len(file) == 0 {
data = innerpermtable
} else {
var err error
data, err = os.ReadFile(file[0])
if err != nil {
return err
}
}
var cfg Perm
if err := yaml.Unmarshal(data, &cfg); err != nil {
return err
}
ag.perm = &cfg
return nil
}