social.mx raw
1 package acl
2
3 import (
4 "bytes"
5 "time"
6
7 "smesh.lol/pkg/grapevine"
8 "smesh.lol/pkg/store"
9 )
10
11 // Social is a WoT-depth-based ACL. Uses the grapevine package to
12 // compute follow-graph depth from admin seeds. Pubkeys at different
13 // depths get different treatment (the server can query depth for
14 // throttle decisions).
15 type Social struct {
16 wot *grapevine.WoT
17 admins [][]byte
18 maxDepth int
19 refreshSec int
20 lastRefresh int64
21 depthMap map[string]int
22 }
23
24 func NewSocial(s *store.Engine, adminHexPubkeys []string, maxDepth, refreshSec int) *Social {
25 admins := [][]byte{:0:len(adminHexPubkeys)}
26 for _, h := range adminHexPubkeys {
27 if pk := hexDec(h); len(pk) == 32 {
28 admins = append(admins, pk)
29 }
30 }
31 sc := &Social{
32 wot: grapevine.New(s),
33 admins: admins,
34 maxDepth: maxDepth,
35 refreshSec: refreshSec,
36 depthMap: map[string]int{},
37 }
38 sc.refresh()
39 return sc
40 }
41
42 func (s *Social) AllowWrite(pubkey []byte, _ uint16) bool {
43 s.maybeRefresh()
44 for _, a := range s.admins {
45 if bytes.Equal(a, pubkey) {
46 return true
47 }
48 }
49 _, known := s.depthMap[string(pubkey)]
50 return known
51 }
52
53 func (s *Social) AllowRead([]byte) bool { return true }
54
55 // Depth returns the WoT depth for a pubkey. 0 = admin, -1 = outsider.
56 func (s *Social) Depth(pubkey []byte) int {
57 s.maybeRefresh()
58 for _, a := range s.admins {
59 if bytes.Equal(a, pubkey) {
60 return 0
61 }
62 }
63 if d, ok := s.depthMap[string(pubkey)]; ok {
64 return d
65 }
66 return -1
67 }
68
69 func (s *Social) maybeRefresh() {
70 now := time.Now().Unix()
71 if now-s.lastRefresh < int64(s.refreshSec) {
72 return
73 }
74 s.refresh()
75 }
76
77 func (s *Social) refresh() {
78 s.lastRefresh = time.Now().Unix()
79 m := map[string]int{}
80 for _, admin := range s.admins {
81 scores := s.wot.Compute(admin, s.maxDepth)
82 for _, sc := range scores {
83 key := string(sc.Pubkey)
84 if existing, ok := m[key]; ok && existing <= sc.Depth {
85 continue
86 }
87 m[key] = sc.Depth
88 }
89 }
90 s.depthMap = m
91 }
92