Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}