access.gno
3.10 Kb ยท 136 lines
1package access
2
3import (
4 "chain"
5 "chain/runtime"
6 "strings"
7
8 "gno.land/p/nt/ufmt"
9)
10
11var roleAddresses map[string]address
12
13func init() {
14 roleAddresses = make(map[string]address)
15}
16
17// SetRoleAddress sets or updates a role's address.
18// Creates the role if it doesn't exist, updates it if it does.
19//
20// Parameters:
21// - cur: current realm (required by interrealm spec; not used directly)
22// - roleName: name of the role
23// - roleAddress: address for the role
24//
25// Only callable by RBAC contract.
26func SetRoleAddress(cur realm, roleName string, roleAddress address) {
27 caller := runtime.PreviousRealm().Address()
28 assertIsRBAC(caller)
29
30 // capture old value for event
31 oldAddr, _ := roleAddresses[strings.TrimSpace(roleName)]
32
33 if err := setRoleAddress(roleName, roleAddress); err != nil {
34 panic(err)
35 }
36
37 chain.Emit(
38 "SetRoleAddress",
39 "prevAddr", caller.String(),
40 "role", roleName,
41 "prevRoleAddr", oldAddr.String(),
42 "roleAddress", roleAddress.String(),
43 )
44}
45
46// setRoleAddress is the internal implementation of SetRoleAddress.
47// Separated for testability.
48func setRoleAddress(roleName string, roleAddress address) error {
49 roleName = strings.TrimSpace(roleName)
50 if roleName == "" {
51 panic("role name cannot be empty")
52 }
53
54 // Validate address
55 if !roleAddress.IsValid() || roleAddress == address("") {
56 return ufmt.Errorf(errInvalidAddress, roleName, roleAddress)
57 }
58
59 roleAddresses[roleName] = roleAddress
60 return nil
61}
62
63// RemoveRole removes a role from the system.
64//
65// Parameters:
66// - roleName: name of the role to remove
67//
68// Only callable by RBAC contract.
69func RemoveRole(cur realm, roleName string) {
70 caller := runtime.PreviousRealm().Address()
71 assertIsRBAC(caller)
72
73 // Validate role name
74 roleName = strings.TrimSpace(roleName)
75 if roleName == "" {
76 panic("role name cannot be empty")
77 }
78
79 if _, ok := roleAddresses[roleName]; !ok {
80 panic(ufmt.Errorf("role %s does not exist", roleName))
81 }
82
83 delete(roleAddresses, roleName)
84
85 chain.Emit(
86 "RemoveRole",
87 "prevAddr", caller.String(),
88 "role", roleName,
89 )
90}
91
92// IsAuthorized checks if caller has the specified role.
93//
94// Parameters:
95// - role: role name to check
96// - caller: address to verify
97//
98// Returns true if authorized, false otherwise.
99func IsAuthorized(role string, caller address) bool {
100 addr, ok := GetAddress(role)
101 if !ok {
102 return false
103 }
104
105 return caller == addr
106}
107
108// GetAddress returns the address for a role and whether it exists.
109func GetAddress(role string) (address, bool) {
110 role = strings.TrimSpace(role)
111 addr, ok := roleAddresses[role]
112 return addr, ok
113}
114
115// GetRoleAddresses returns a copy of all role addresses.
116func GetRoleAddresses() map[string]address {
117 addresses := make(map[string]address)
118
119 for role, data := range roleAddresses {
120 addresses[role] = data
121 }
122
123 return addresses
124}
125
126// MustGetAddress returns the address for a role or panics if it doesn't exist.
127// Use this when the role is expected to exist and failure is critical.
128func MustGetAddress(role string) address {
129 role = strings.TrimSpace(role)
130 addr, ok := GetAddress(role)
131 if !ok {
132 panic(ufmt.Errorf(errRoleNotFound, role))
133 }
134
135 return addr
136}