authorizable.gno
2.90 Kb · 114 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 "chain/runtime"
10
11 "gno.land/p/nt/avl/v0"
12 "gno.land/p/nt/ownable/v0"
13 "gno.land/p/nt/ufmt/v0"
14)
15
16type Authorizable struct {
17 *ownable.Ownable // owner in ownable is superuser
18 authorized *avl.Tree // chain.Addr > struct{}{}
19}
20
21// New creates an Authorizable from an existing *ownable.Ownable.
22// The owner is automatically added to the auth list.
23// The auth mode (current-realm vs previous-realm) is inherited from the
24// provided Ownable. Use the ownable constructors to choose the mode:
25//
26// // Current-realm auth (caller is the realm making the call):
27// authorizable.New(ownable.New())
28//
29// // Previous-realm auth (caller is the user/realm one step back):
30// authorizable.New(ownable.NewWithOrigin())
31//
32// // Explicit address, current-realm auth:
33// authorizable.New(ownable.NewWithAddress(addr))
34//
35// // Explicit address, previous-realm auth:
36// authorizable.New(ownable.NewWithAddressByPrevious(addr))
37func New(o *ownable.Ownable) *Authorizable {
38 a := &Authorizable{
39 Ownable: o,
40 authorized: avl.NewTree(),
41 }
42
43 // Add owner to auth list
44 a.authorized.Set(a.Owner().String(), struct{}{})
45 return a
46}
47
48func (a *Authorizable) AddToAuthList(addr address) error {
49 if !a.Owned() {
50 return ErrNotSuperuser
51 }
52 return a.addToAuthList(addr)
53}
54
55func (a *Authorizable) addToAuthList(addr address) error {
56 if _, exists := a.authorized.Get(addr.String()); exists {
57 return ErrAlreadyInList
58 }
59
60 a.authorized.Set(addr.String(), struct{}{})
61
62 return nil
63}
64
65func (a *Authorizable) DeleteFromAuthList(addr address) error {
66 if !a.Owned() {
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
85func (a *Authorizable) OnAuthList() error {
86 current := runtime.CurrentRealm().Address()
87 return a.onAuthList(current)
88}
89
90func (a *Authorizable) PreviousOnAuthList() error {
91 previous := runtime.PreviousRealm().Address()
92 return a.onAuthList(previous)
93}
94
95func (a *Authorizable) onAuthList(caller address) error {
96 if !a.authorized.Has(caller.String()) {
97 return ErrNotInAuthList
98 }
99 return nil
100}
101
102func (a Authorizable) AssertOnAuthList() {
103 err := a.OnAuthList()
104 if err != nil {
105 panic(err)
106 }
107}
108
109func (a Authorizable) AssertPreviousOnAuthList() {
110 err := a.PreviousOnAuthList()
111 if err != nil {
112 panic(err)
113 }
114}