Search Apps Documentation Source Content File Folder Download Copy Actions Download 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}