Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}