admins.gno
2.01 Kb · 66 lines
1// Package admins lets a fixed set of addresses change a realm's gnotif
2// triggers. The realm passes the handle gnotif.Open returned straight to New,
3// keeps the *Admins unexported, and on each call gives its gnotif identity,
4// minted in the crossing function the admin called.
5package admins
6
7import (
8 "chain/runtime"
9 "strings"
10
11 "gno.land/p/nym-gfanton001/gnotif/trigger/v0"
12)
13
14// Handle is the method set of the registry's *Handle.
15type Handle interface {
16 Set(cur realm, name string, t trigger.Trigger) string
17 Remove(cur realm, name string)
18}
19
20// Admins holds a realm's handle and the addresses allowed to use it.
21type Admins struct {
22 h Handle
23 admins map[address]bool
24}
25
26// New returns an Admins over the handle h. It panics with no admin.
27func New(h Handle, addrs ...address) *Admins {
28 if len(addrs) == 0 {
29 panic("at least one admin")
30 }
31 a := &Admins{h: h, admins: make(map[address]bool, len(addrs))}
32 for _, addr := range addrs {
33 if !addr.IsValid() {
34 panic("invalid admin address " + addr.String())
35 }
36 // A caller's address is lower case; bech32 also allows upper case.
37 a.admins[address(strings.ToLower(string(addr)))] = true
38 }
39 return a
40}
41
42// Set stores t under name and returns its id, when the realm's caller is an
43// admin. me is the realm's gnotif identity, cur.Sub(gnotif.Subpath), and its
44// Previous is the caller.
45func (a *Admins) Set(_ int, me realm, name string, t trigger.Trigger) string {
46 a.mustAdmin(0, me)
47 return a.h.Set(cross(me), name, t)
48}
49
50// Remove removes the trigger under name, when the realm's caller is an admin.
51func (a *Admins) Remove(_ int, me realm, name string) {
52 a.mustAdmin(0, me)
53 a.h.Remove(cross(me), name)
54}
55
56func (a *Admins) mustAdmin(_ int, me realm) {
57 if !me.IsCurrent() {
58 panic("me is not current: mint it in the crossing function the admin called")
59 }
60 if _, _, _, isSession := runtime.GetSessionInfo(); isSession {
61 panic("sign with your own key, not a session key")
62 }
63 if caller := me.Previous().Address(); !a.admins[caller] {
64 panic(caller.String() + " is not an admin")
65 }
66}