Introduce ACL registry with follows implementation, enhance SaveEvent for replaceable kinds, and refactor filter-based serial fetching. Update configs and dependencies.
This commit is contained in:
127
pkg/acl/follows.go
Normal file
127
pkg/acl/follows.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package acl
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
database "database.orly"
|
||||
"database.orly/indexes/types"
|
||||
"encoders.orly/bech32encoding"
|
||||
"encoders.orly/event"
|
||||
"encoders.orly/filter"
|
||||
"encoders.orly/hex"
|
||||
"encoders.orly/kind"
|
||||
"encoders.orly/tag"
|
||||
"lol.mleku.dev/chk"
|
||||
"lol.mleku.dev/errorf"
|
||||
"lol.mleku.dev/log"
|
||||
"next.orly.dev/app/config"
|
||||
utils "utils.orly"
|
||||
)
|
||||
|
||||
type Follows struct {
|
||||
cfg *config.C
|
||||
*database.D
|
||||
followsMx sync.RWMutex
|
||||
admins [][]byte
|
||||
follows [][]byte
|
||||
}
|
||||
|
||||
func (f *Follows) Configure(cfg ...any) (err error) {
|
||||
log.I.F("configuring follows ACL")
|
||||
for _, ca := range cfg {
|
||||
switch c := ca.(type) {
|
||||
case *config.C:
|
||||
log.D.F("setting ACL config: %v", c)
|
||||
f.cfg = c
|
||||
case *database.D:
|
||||
log.D.F("setting ACL database: %s", c.Path())
|
||||
f.D = c
|
||||
default:
|
||||
err = errorf.E("invalid type: %T", reflect.TypeOf(ca))
|
||||
}
|
||||
}
|
||||
if f.cfg == nil || f.D == nil {
|
||||
err = errorf.E("both config and database must be set")
|
||||
return
|
||||
}
|
||||
// find admin follow lists
|
||||
f.followsMx.Lock()
|
||||
defer f.followsMx.Unlock()
|
||||
log.I.F("finding admins")
|
||||
f.follows, f.admins = nil, nil
|
||||
for _, admin := range f.cfg.Admins {
|
||||
log.I.F("%s", admin)
|
||||
var adm []byte
|
||||
if adm, err = bech32encoding.NpubOrHexToPublicKeyBinary(admin); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
log.I.F("admin: %0x", adm)
|
||||
f.admins = append(f.admins, adm)
|
||||
fl := &filter.F{
|
||||
Authors: tag.NewFromAny(adm),
|
||||
Kinds: kind.NewS(kind.New(kind.FollowList.K)),
|
||||
}
|
||||
var idxs []database.Range
|
||||
if idxs, err = database.GetIndexesFromFilter(fl); chk.E(err) {
|
||||
return
|
||||
}
|
||||
var sers types.Uint40s
|
||||
for _, idx := range idxs {
|
||||
var s types.Uint40s
|
||||
if s, err = f.D.GetSerialsByRange(idx); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
sers = append(sers, s...)
|
||||
}
|
||||
if len(sers) > 0 {
|
||||
for _, s := range sers {
|
||||
var ev *event.E
|
||||
if ev, err = f.D.FetchEventBySerial(s); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
log.I.F("admin follow list:\n%s", ev.Serialize())
|
||||
for _, v := range ev.Tags.GetAll([]byte("p")) {
|
||||
log.I.F("adding follow: %s", v.Value())
|
||||
var a []byte
|
||||
if a, err = hex.Dec(string(v.Value())); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
f.follows = append(f.follows, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *Follows) GetAccessLevel(pub []byte) (level string) {
|
||||
if f.cfg == nil {
|
||||
return "write"
|
||||
}
|
||||
f.followsMx.RLock()
|
||||
defer f.followsMx.RUnlock()
|
||||
for _, v := range f.admins {
|
||||
if utils.FastEqual(v, pub) {
|
||||
return "admin"
|
||||
}
|
||||
}
|
||||
for _, v := range f.follows {
|
||||
if utils.FastEqual(v, pub) {
|
||||
return "write"
|
||||
}
|
||||
}
|
||||
return "read"
|
||||
}
|
||||
|
||||
func (f *Follows) GetACLInfo() (name, description, documentation string) {
|
||||
return "follows", "whitelist follows of admins",
|
||||
`This ACL mode searches for follow lists of admins and grants all followers write access`
|
||||
}
|
||||
|
||||
func (f *Follows) Type() string { return "follows" }
|
||||
|
||||
func init() {
|
||||
log.T.F("registering follows ACL")
|
||||
Registry.Register(new(Follows))
|
||||
}
|
||||
Reference in New Issue
Block a user