rbac.gno
5.23 Kb ยท 185 lines
1package rbac
2
3import (
4 "chain/runtime"
5 "strings"
6)
7
8// RBAC encapsulates and manages roles and their permissions.
9// It combines role management with two-step ownership transfer functionality.
10type RBAC struct {
11 ownable *Ownable2Step
12 // roles maps role names to their respective `Role` objects
13 roles map[string]*Role
14}
15
16// New creates a new RBAC instance with the origin caller as owner.
17func New() *RBAC {
18 return &RBAC{
19 ownable: newOwnable2StepWithAddress(runtime.OriginCaller()),
20 roles: make(map[string]*Role),
21 }
22}
23
24// NewRBACWithAddress creates a new RBAC instance with addr as owner.
25func NewRBACWithAddress(addr address) *RBAC {
26 return &RBAC{
27 ownable: newOwnable2StepWithAddress(addr),
28 roles: make(map[string]*Role),
29 }
30}
31
32// IsAuthorized checks if addr has the specified roleName. Returns false if the role does not exist.
33func (rb *RBAC) IsAuthorized(roleName string, addr address) bool {
34 role, exists := rb.roles[roleName]
35 if !exists {
36 return false
37 }
38
39 return role.IsAuthorized(addr)
40}
41
42// RegisterRole registers a new role with given role name and address.
43//
44// Errors:
45// `RegisterRole` returns an error in the following situations:
46// - `ErrInvalidRoleName`: role name is an empty string or contains only whitespace
47// - `ErrRoleAlreadyExists`: the role to be registered already exists in rbac.
48// Since system roles are registered through `initRbac`, attempting to register
49// a new role with a system role name will return an `ErrRoleAlreadyExists` error.
50func (rb *RBAC) RegisterRole(roleName string, addr address) error {
51 roleName = strings.TrimSpace(roleName)
52 if roleName == "" {
53 return ErrInvalidRoleName
54 }
55
56 if rb.existsRole(roleName) {
57 return ErrRoleAlreadyExists
58 }
59
60 rb.roles[roleName] = NewRole(roleName, addr)
61
62 return nil
63}
64
65// UpdateRoleAddress assigns addr to roleName.
66//
67// Errors:
68// - `ErrInvalidRoleName`: role name is an empty string or contains only whitespace
69// - `ErrRoleDoesNotExist`: the specified role does not exist in the RBAC system
70// - `ErrInvalidAddress`: addr is empty or has an invalid format
71func (rb *RBAC) UpdateRoleAddress(roleName string, addr address) error {
72 roleName = strings.TrimSpace(roleName)
73 if roleName == "" {
74 return ErrInvalidRoleName
75 }
76
77 role, exists := rb.roles[roleName]
78 if !exists {
79 return ErrRoleDoesNotExist
80 }
81
82 if addr == zeroAddress || !addr.IsValid() {
83 return ErrInvalidAddress
84 }
85
86 role.setAddress(addr)
87
88 return nil
89}
90
91// RemoveRole removes roleName from the RBAC system.
92//
93// Errors:
94// - `ErrInvalidRoleName`: role name is an empty string or contains only whitespace
95// - `ErrRoleDoesNotExist`: the specified role does not exist in the RBAC system
96// - `ErrCannotRemoveSystemRole`: attempting to remove a system role (e.g., admin, governance, pool, etc.)
97func (rb *RBAC) RemoveRole(roleName string) error {
98 roleName = strings.TrimSpace(roleName)
99 if roleName == "" {
100 return ErrInvalidRoleName
101 }
102
103 if !rb.existsRole(roleName) {
104 return ErrRoleDoesNotExist
105 }
106
107 // Check if it's a system role
108 if IsSystemRole(roleName) {
109 return ErrCannotRemoveSystemRole
110 }
111
112 // Simply delete the role since permissions are no longer managed here
113 delete(rb.roles, roleName)
114
115 return nil
116}
117
118// GetAllRoleAddresses returns a map of all role names to their assigned addresses.
119func (rb *RBAC) GetAllRoleAddresses() map[string]address {
120 addresses := make(map[string]address)
121
122 for roleName, role := range rb.roles {
123 addresses[roleName] = role.Address()
124 }
125
126 return addresses
127}
128
129// GetRoleAddress returns the address assigned to roleName.
130//
131// Errors:
132// - `ErrRoleDoesNotExist`: the specified role does not exist in the RBAC system
133func (rb *RBAC) GetRoleAddress(roleName string) (address, error) {
134 role, exists := rb.roles[roleName]
135 if !exists {
136 return "", ErrRoleDoesNotExist
137 }
138
139 return role.Address(), nil
140}
141
142// Owner returns the current owner address.
143func (rb *RBAC) Owner() address {
144 return rb.ownable.Owner()
145}
146
147// PendingOwner returns the pending owner address during ownership transfer.
148func (rb *RBAC) PendingOwner() address {
149 return rb.ownable.PendingOwner()
150}
151
152// AcceptOwnershipBy completes the ownership transfer process.
153// Must be called by the pending owner.
154//
155// Errors:
156// - `ErrNoPendingOwner`: no ownership transfer is pending
157// - `ErrPendingUnauthorized`: addr is not the pending owner
158func (rb *RBAC) AcceptOwnershipBy(addr address) error {
159 return rb.ownable.AcceptOwnershipBy(addr)
160}
161
162// DropOwnershipBy removes the owner, effectively disabling owner-only actions.
163// This is irreversible and will prevent any future owner-only operations.
164//
165// Errors:
166// - `ErrUnauthorized`: addr is not the current owner
167func (rb *RBAC) DropOwnershipBy(addr address) error {
168 return rb.ownable.DropOwnershipBy(addr)
169}
170
171// TransferOwnershipBy initiates the two-step ownership transfer process.
172// The newOwner must call AcceptOwnershipBy to complete the transfer.
173//
174// Errors:
175// - `ErrUnauthorized`: caller is not the current owner
176// - `ErrInvalidAddress`: newOwner is empty or has an invalid format
177func (rb *RBAC) TransferOwnershipBy(newOwner, caller address) error {
178 return rb.ownable.TransferOwnershipBy(newOwner, caller)
179}
180
181// existsRole checks if name exists in the RBAC system.
182func (rb *RBAC) existsRole(name string) bool {
183 _, exists := rb.roles[name]
184 return exists
185}