package acl import ( "git.smesh.lol/moxie/pkg/mxutil" "bytes" "time" "git.smesh.lol/morly/pkg/grapevine" "git.smesh.lol/morly/pkg/store" ) // Social is a WoT-depth-based ACL. Uses the grapevine package to // compute follow-graph depth from admin seeds. Pubkeys at different // depths get different treatment (the server can query depth for // throttle decisions). type Social struct { wot *grapevine.WoT admins [][]byte maxDepth int32 refreshSec int32 lastRefresh int64 depthMap map[string]int32 } func NewSocial(s *store.Engine, adminHexPubkeys []string, maxDepth, refreshSec int32) (sv *Social) { admins := [][]byte{:0:len(adminHexPubkeys)} for _, h := range adminHexPubkeys { if pk := hexDec(h); len(pk) == 32 { admins = mxutil.Ensure(admins, 1) admins = push(admins, pk) } } sc := &Social{ wot: grapevine.New(s), admins: admins, maxDepth: maxDepth, refreshSec: refreshSec, depthMap: map[string]int32{}, } sc.refresh() return sc } func (s *Social) AllowWrite(pubkey []byte, _ uint16) (ok bool) { s.maybeRefresh() for _, a := range s.admins { if bytes.Equal(a, pubkey) { return true } } _, known := s.depthMap[string(pubkey)] return known } func (s *Social) AllowRead([]byte) (ok bool) { return true } // Depth returns the WoT depth for a pubkey. 0 = admin, -1 = outsider. func (s *Social) Depth(pubkey []byte) (n int32) { s.maybeRefresh() for _, a := range s.admins { if bytes.Equal(a, pubkey) { return 0 } } if d, ok := s.depthMap[string(pubkey)]; ok { return d } return -1 } func (s *Social) maybeRefresh() { now := time.Now().Unix() if now-s.lastRefresh < int64(s.refreshSec) { return } s.refresh() } func (s *Social) refresh() { s.lastRefresh = time.Now().Unix() m := map[string]int32{} // Declared outside the loops: a declaration in the body of a self-mutating // method allocates in the sovereign arena on every iteration. var scores []grapevine.Score var key string for _, admin := range s.admins { scores = s.wot.Compute(admin, s.maxDepth) for _, sc := range scores { key = string(sc.Pubkey) if existing, ok := m[key]; ok && existing <= sc.Depth { continue } m[key] = sc.Depth } } s.depthMap = m }