acl.gno
4.68 Kb · 175 lines
1package memba_notes_v1
2
3import (
4 keys "gno.land/r/samcrew/enckeys_v1"
5 "strings"
6)
7
8func writer(n *note, who address) bool {
9 for _, a := range n.Writers {
10 if a == who {
11 return true
12 }
13 }
14 return false
15}
16func canWrite(cur realm, n *note, who address) bool {
17 if who == n.Owner {
18 return true
19 }
20 if n.Mode == ModePublicOpen {
21 return false
22 }
23 if writer(n, who) {
24 return true
25 }
26 if encrypted(n.Mode) && !contains(n.Readers, who) {
27 return false
28 }
29 if n.GovWriters && n.Owner == govAddress && govMember(who) {
30 return true
31 }
32 return policyAllows(cur, n, who, OpWrite)
33}
34func requireWrite(cur realm, n *note, who address) {
35 if !canWrite(cur, n, who) {
36 panic("notes: writer required")
37 }
38}
39func AddWriter(cur realm, id [16]byte, baseRevision uint64, to address, opID [16]byte) {
40 who := enter(cur, false)
41 defer leave()
42 mutateAddWriter(cur, who, id, baseRevision, to, opID)
43}
44func mutateAddWriter(cur realm, who address, id [16]byte, baseRevision uint64, to address, opID [16]byte) {
45 n := live(id)
46 owner(n, who)
47 expected(n, baseRevision)
48 if !public(n.Mode) {
49 panic("notes: encrypted ACL requires atomic manifest")
50 }
51 to = keys.CanonicalAddress(to)
52 if to == n.Owner || writer(n, to) {
53 panic("notes: writer already present")
54 }
55 if len(n.Writers) >= MaxReaders {
56 panic("notes: too many writers")
57 }
58 operation(n, opID)
59 n.Writers = append(n.Writers, to)
60 sharedIndex.Set(string(to)+":"+indexKey(n), idText(id))
61 bump(n, who, opID, "writer-add")
62}
63func RemoveWriter(cur realm, id [16]byte, baseRevision uint64, to address, opID [16]byte) {
64 who := enter(cur, false)
65 defer leave()
66 mutateRemoveWriter(cur, who, id, baseRevision, to, opID)
67}
68func mutateRemoveWriter(cur realm, who address, id [16]byte, baseRevision uint64, to address, opID [16]byte) {
69 n := live(id)
70 owner(n, who)
71 expected(n, baseRevision)
72 if !public(n.Mode) {
73 panic("notes: encrypted ACL requires rotation")
74 }
75 to = keys.CanonicalAddress(to)
76 if !writer(n, to) {
77 panic("notes: writer missing")
78 }
79 operation(n, opID)
80 for i, a := range n.Writers {
81 if a == to {
82 n.Writers = append(n.Writers[:i], n.Writers[i+1:]...)
83 break
84 }
85 }
86 sharedIndex.Remove(string(to) + ":" + indexKey(n))
87 bump(n, who, opID, "writer-remove")
88}
89func ProposeOwner(cur realm, id [16]byte, baseRevision uint64, to address, opID [16]byte) {
90 who := enter(cur, false)
91 defer leave()
92 mutateProposeOwner(cur, who, id, baseRevision, to, opID)
93}
94func mutateProposeOwner(cur realm, who address, id [16]byte, baseRevision uint64, to address, opID [16]byte) {
95 n := live(id)
96 owner(n, who)
97 expected(n, baseRevision)
98 if to != "" {
99 to = keys.CanonicalAddress(to)
100 }
101 if to == n.Owner {
102 panic("notes: already owner")
103 }
104 operation(n, opID)
105 n.PendingOwner = to
106 bump(n, who, opID, "owner-propose")
107}
108func AcceptOwnership(cur realm, id [16]byte, baseRevision uint64, opID [16]byte) {
109 who := enter(cur, false)
110 defer leave()
111 mutateAcceptOwnership(cur, who, id, baseRevision, opID)
112}
113func mutateAcceptOwnership(cur realm, who address, id [16]byte, baseRevision uint64, opID [16]byte) {
114 n := live(id)
115 expected(n, baseRevision)
116 if n.PendingOwner == "" || who != n.PendingOwner {
117 panic("notes: pending owner required")
118 }
119 isRealm := strings.HasPrefix(cur.Previous().PkgPath(), "gno.land/r/") || who == govAddress
120 if encrypted(n.Mode) && (!isRealm && !contains(n.Readers, who) || isRealm && n.Mode == ModePrivate) {
121 panic("notes: encrypted ownership requires current wrap/shared mode")
122 }
123 if n.OwnerGeneration == ^uint64(0) {
124 panic("notes: owner generation exhausted")
125 }
126 operation(n, opID)
127 unindex(n)
128 n.OwnerIsRealm = isRealm
129 resetPublicWrites(n)
130 n.Owner = who
131 n.PendingOwner = ""
132 n.OwnerGeneration++
133 n.GovWriters = false
134 if encrypted(n.Mode) {
135 preserveTransferredWriters(n)
136 }
137 index(n)
138 bump(n, who, opID, "owner-accept")
139}
140func SetListed(cur realm, id [16]byte, baseRevision uint64, listed bool, opID [16]byte) {
141 who := enter(cur, false)
142 defer leave()
143 mutateSetListed(cur, who, id, baseRevision, listed, opID)
144}
145func mutateSetListed(cur realm, who address, id [16]byte, baseRevision uint64, listed bool, opID [16]byte) {
146 n := live(id)
147 if who != n.Owner && moderator(who) {
148 mutateModerateListing(cur, who, id, baseRevision, listed, opID)
149 return
150 }
151 owner(n, who)
152 expected(n, baseRevision)
153 if !public(n.Mode) {
154 panic("notes: public note required")
155 }
156 operation(n, opID)
157 unindex(n)
158 n.Listed = listed
159 index(n)
160 bump(n, who, opID, "listing")
161}
162func WritersJSON(idHex string) string {
163 n := find(readID(idHex))
164 out := "["
165 for i, a := range n.Writers {
166 if i > 0 {
167 out += ","
168 }
169 out += q(string(a))
170 }
171 return out + "]"
172}
173func ListSharedWithJSON(addr address, cursor string, limit int) string {
174 return page(sharedIndex, string(keys.CanonicalAddress(addr))+":", cursor, limit)
175}