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