mirror of
https://github.com/fumiama/go-onebot-agent.git
synced 2026-06-05 02:00:23 +08:00
119 lines
2.4 KiB
Go
119 lines
2.4 KiB
Go
package goba
|
|
|
|
import (
|
|
_ "embed"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/RomiChan/syncx"
|
|
"github.com/pkg/errors"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
var (
|
|
ErrNoSuchPermRole = errors.New("no such perm role")
|
|
ErrUnexpectedAction = errors.New("unexpected action")
|
|
)
|
|
|
|
// PermRole 和 yaml config 一一对应
|
|
type PermRole string
|
|
|
|
const (
|
|
PermRoleOwner PermRole = "owner" // PermRoleOwner 群主或主人
|
|
PermRoleAdmin PermRole = "admin" // PermRoleAdmin 管理
|
|
PermRoleUser PermRole = "user" // PermRoleUser 普通用户
|
|
)
|
|
|
|
//go:embed actions.yaml
|
|
var innerpermtable []byte
|
|
|
|
// PermAction 记录 action 的描述和 params
|
|
type PermAction struct {
|
|
Desc string `yaml:"desc"`
|
|
Params string `yaml:"params"`
|
|
}
|
|
|
|
// 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|\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('|')
|
|
}
|
|
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
|
|
}
|