Search Apps Documentation Source Content File Folder Download Copy Actions Download

authorizable.gno

3.58 Kb · 124 lines
  1// Package authorizable is an extension of p/nt/ownable;
  2// It allows the user to instantiate an Authorizable struct, which extends
  3// p/nt/ownable with a list of users that are authorized for something.
  4// By using authorizable, you have a superuser (ownable), as well as another
  5// authorization level, which can be used for adding moderators or similar to your realm.
  6package authorizable
  7
  8import (
  9	"gno.land/p/nt/bptree/v0"
 10	"gno.land/p/nt/ownable/v0"
 11	"gno.land/p/nt/ufmt/v0"
 12)
 13
 14type Authorizable struct {
 15	*ownable.Ownable                // owner in ownable is superuser
 16	authorized       *bptree.BPTree // chain.Addr > struct{}{}
 17}
 18
 19// New creates an Authorizable from an existing *ownable.Ownable.
 20// The owner is automatically added to the auth list.
 21//
 22// Example construction:
 23//
 24//	authorizable.New(ownable.NewWithAddress(addr))
 25func New(o *ownable.Ownable) *Authorizable {
 26	a := &Authorizable{
 27		Ownable:    o,
 28		authorized: bptree.NewBPTree32(),
 29	}
 30
 31	// Add owner to auth list
 32	a.authorized.Set(a.Owner().String(), struct{}{})
 33	return a
 34}
 35
 36// AddToAuthList adds addr to the auth list. rlm must be the caller's
 37// own captured cur; rlm.Previous().Address() must equal the superuser
 38// (the underlying Ownable's owner).
 39func (a *Authorizable) AddToAuthList(_ int, rlm realm, addr address) error {
 40	if !rlm.IsCurrent() {
 41		return ErrNotSuperuser
 42	}
 43	if !a.OwnedBy(rlm.Previous().Address()) {
 44		return ErrNotSuperuser
 45	}
 46	return a.addToAuthList(addr)
 47}
 48
 49func (a *Authorizable) addToAuthList(addr address) error {
 50	if _, exists := a.authorized.Get(addr.String()); exists {
 51		return ErrAlreadyInList
 52	}
 53
 54	a.authorized.Set(addr.String(), struct{}{})
 55
 56	return nil
 57}
 58
 59// DeleteFromAuthList removes addr from the auth list. rlm must be the
 60// caller's own captured cur; rlm.Previous().Address() must equal the
 61// superuser (the underlying Ownable's owner).
 62func (a *Authorizable) DeleteFromAuthList(_ int, rlm realm, addr address) error {
 63	if !rlm.IsCurrent() {
 64		return ErrNotSuperuser
 65	}
 66	if !a.OwnedBy(rlm.Previous().Address()) {
 67		return ErrNotSuperuser
 68	}
 69	return a.deleteFromAuthList(addr)
 70}
 71
 72func (a *Authorizable) deleteFromAuthList(addr address) error {
 73	if !a.authorized.Has(addr.String()) {
 74		return ErrNotInAuthList
 75	}
 76
 77	if _, removed := a.authorized.Remove(addr.String()); !removed {
 78		str := ufmt.Sprintf("authorizable: could not remove %s from auth list", addr.String())
 79		panic(str)
 80	}
 81
 82	return nil
 83}
 84
 85// OnAuthList reports whether rlm.Address() is on the auth list. rlm
 86// must be the caller's own captured cur (asserted via rlm.IsCurrent()).
 87// Pre-migration shape used unsafe.CurrentRealm().Address() — vulnerable
 88// to the .Title()-class read where a non-crossing wrapper made the walk
 89// return the wrong realm. Explicit rlm closes that.
 90func (a *Authorizable) OnAuthList(_ int, rlm realm) error {
 91	if !rlm.IsCurrent() {
 92		return ErrNotInAuthList
 93	}
 94	return a.onAuthList(rlm.Address())
 95}
 96
 97// PreviousOnAuthList reports whether rlm.Previous().Address() — the
 98// realm that crossed into the caller — is on the auth list. Same rlm
 99// contract as OnAuthList.
100func (a *Authorizable) PreviousOnAuthList(_ int, rlm realm) error {
101	if !rlm.IsCurrent() {
102		return ErrNotInAuthList
103	}
104	return a.onAuthList(rlm.Previous().Address())
105}
106
107func (a *Authorizable) onAuthList(caller address) error {
108	if !a.authorized.Has(caller.String()) {
109		return ErrNotInAuthList
110	}
111	return nil
112}
113
114func (a Authorizable) AssertOnAuthList(_ int, rlm realm) {
115	if err := a.OnAuthList(0, rlm); err != nil {
116		panic(err)
117	}
118}
119
120func (a Authorizable) AssertPreviousOnAuthList(_ int, rlm realm) {
121	if err := a.PreviousOnAuthList(0, rlm); err != nil {
122		panic(err)
123	}
124}