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