access_control.gno
2.12 Kb · 78 lines
1package accesscontrol
2
3import "chain/runtime/unsafe"
4
5// AuthCheck must be owned by the calling realm/package.
6// Do not pass callbacks received from untrusted callers.
7type AuthCheck func(address) bool
8
9func AssertCurrentRealm(_ int, rlm realm) {
10 if !rlm.IsCurrent() {
11 panic("spoofed realm")
12 }
13}
14
15func AssertIsAdmin(_ int, rlm realm, isAdmin AuthCheck) {
16 MustGetAdminCaller(0, rlm, isAdmin)
17}
18
19func MustGetAdminCaller(_ int, rlm realm, isAdmin AuthCheck) address {
20 assertAuthCheck(isAdmin, "admin auth check is nil")
21 AssertCurrentRealm(0, rlm)
22
23 caller := rlm.Previous().Address()
24 if !isAdmin(caller) {
25 panic("admin access required")
26 }
27 return caller
28}
29
30func MustGetUserCaller(_ int, rlm realm) address {
31 AssertCurrentRealm(0, rlm)
32
33 prev := rlm.Previous()
34 if !prev.IsUserCall() {
35 panic("contract calls not allowed: function must be called directly by user")
36 }
37 return prev.Address()
38}
39
40// AssertIsAdminOrigin checks the transaction signer, not the direct caller realm.
41// Use it only for explicit delegation APIs that intentionally allow code-realm relays.
42func AssertIsAdminOrigin(isAdmin AuthCheck) {
43 MustGetAdminOrigin(isAdmin)
44}
45
46// MustGetAdminOrigin checks the transaction signer, not the direct caller realm.
47// Use it only for explicit delegation APIs that intentionally allow code-realm relays.
48func MustGetAdminOrigin(isAdmin AuthCheck) address {
49 assertAuthCheck(isAdmin, "admin auth check is nil")
50
51 caller := unsafe.OriginCaller()
52 if !isAdmin(caller) {
53 panic("admin access required")
54 }
55 return caller
56}
57
58func AssertIsAdminOrOperator(_ int, rlm realm, isAdmin AuthCheck, isOperator AuthCheck) {
59 MustGetAdminOrOperatorCaller(0, rlm, isAdmin, isOperator)
60}
61
62func MustGetAdminOrOperatorCaller(_ int, rlm realm, isAdmin AuthCheck, isOperator AuthCheck) address {
63 assertAuthCheck(isAdmin, "admin auth check is nil")
64 assertAuthCheck(isOperator, "operator auth check is nil")
65 AssertCurrentRealm(0, rlm)
66
67 caller := rlm.Previous().Address()
68 if !isAdmin(caller) && !isOperator(caller) {
69 panic("admin or operator access required")
70 }
71 return caller
72}
73
74func assertAuthCheck(check AuthCheck, msg string) {
75 if check == nil {
76 panic(msg)
77 }
78}