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