Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}