You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

290 lines
6.9 KiB

package types
import (
"fmt"
. "github.com/tendermint/tendermint/common"
"reflect"
)
//------------------------------------------------------------------------------------------------
var (
GlobalPermissionsAddress = Zero256[:20]
GlobalPermissionsAddress256 = Zero256
DougAddress = append([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, []byte("THISISDOUG")...)
DougAddress256 = LeftPadWord256(DougAddress)
)
// A particular permission
type PermFlag uint64
// Base permission references are like unix (the index is already bit shifted)
const (
Root PermFlag = 1 << iota // 1
Send // 2
Call // 4
CreateContract // 8
CreateAccount // 16
Bond // 32
Name // 64
DefaultBBPB = Send | Call | CreateContract | CreateAccount | Bond | Name
// XXX: must be adjusted if base perms added/removed
NumBasePermissions uint = 7
TopBasePermission PermFlag = 1 << (NumBasePermissions - 1)
AllBasePermissions PermFlag = TopBasePermission | (TopBasePermission - 1)
AllSet PermFlag = AllBasePermissions | AllSNativePermissions
)
// should have same ordering as above
type BasePermissionsString struct {
Root bool `json:"root,omitempty"`
Send bool `json:"send,omitempty"`
Call bool `json:"call,omitempty"`
CreateContract bool `json:"create_contract,omitempty"`
CreateAccount bool `json:"create_account,omitempty"`
Bond bool `json:"bond,omitempty"`
Name bool `json:"name,omitempty"`
}
//---------------------------------------------------------------------------------------------
// Base chain permissions struct
type BasePermissions struct {
// bit array with "has"/"doesn't have" for each permission
Perms PermFlag `json:"perms"`
// bit array with "set"/"not set" for each permission (not-set should fall back to global)
SetBit PermFlag `json:"set"`
}
func NewBasePermissions() *BasePermissions {
return &BasePermissions{0, 0}
}
// Get a permission value. ty should be a power of 2.
// ErrValueNotSet is returned if the permission's set bit is off,
// and should be caught by caller so the global permission can be fetched
func (p *BasePermissions) Get(ty PermFlag) (bool, error) {
if ty == 0 {
return false, ErrInvalidPermission(ty)
}
if p.SetBit&ty == 0 {
return false, ErrValueNotSet(ty)
}
return p.Perms&ty > 0, nil
}
// Set a permission bit. Will set the permission's set bit to true.
func (p *BasePermissions) Set(ty PermFlag, value bool) error {
if ty == 0 {
return ErrInvalidPermission(ty)
}
p.SetBit |= ty
if value {
p.Perms |= ty
} else {
p.Perms &= ^ty
}
return nil
}
// Set the permission's set bit to false
func (p *BasePermissions) Unset(ty PermFlag) error {
if ty == 0 {
return ErrInvalidPermission(ty)
}
p.SetBit &= ^ty
return nil
}
// Check if the permission is set
func (p *BasePermissions) IsSet(ty PermFlag) bool {
if ty == 0 {
return false
}
return p.SetBit&ty > 0
}
func (p *BasePermissions) Copy() *BasePermissions {
if p == nil {
return nil
}
return &BasePermissions{
Perms: p.Perms,
SetBit: p.SetBit,
}
}
func (p *BasePermissions) String() string {
return fmt.Sprintf("Base: %b; Set: %b", p.Perms, p.SetBit)
}
//---------------------------------------------------------------------------------------------
type AccountPermissions struct {
Base *BasePermissions `json:"base"`
Roles []string `json:"roles"`
}
func NewAccountPermissions() *AccountPermissions {
return &AccountPermissions{
Base: NewBasePermissions(),
Roles: []string{},
}
}
// Returns true if the role is found
func (aP *AccountPermissions) HasRole(role string) bool {
role = string(LeftPadBytes([]byte(role), 32))
for _, r := range aP.Roles {
if r == role {
return true
}
}
return false
}
// Returns true if the role is added, and false if it already exists
func (aP *AccountPermissions) AddRole(role string) bool {
role = string(LeftPadBytes([]byte(role), 32))
for _, r := range aP.Roles {
if r == role {
return false
}
}
aP.Roles = append(aP.Roles, role)
return true
}
// Returns true if the role is removed, and false if it is not found
func (aP *AccountPermissions) RmRole(role string) bool {
role = string(LeftPadBytes([]byte(role), 32))
for i, r := range aP.Roles {
if r == role {
post := []string{}
if len(aP.Roles) > i+1 {
post = aP.Roles[i+1:]
}
aP.Roles = append(aP.Roles[:i], post...)
return true
}
}
return false
}
func (aP *AccountPermissions) Copy() *AccountPermissions {
if aP == nil {
return nil
}
r := make([]string, len(aP.Roles))
copy(r, aP.Roles)
return &AccountPermissions{
Base: aP.Base.Copy(),
Roles: r,
}
}
func NewDefaultAccountPermissions() *AccountPermissions {
return &AccountPermissions{
Base: &BasePermissions{
Perms: DefaultBBPB,
SetBit: AllSet,
},
Roles: []string{},
}
}
//---------------------------------------------------------------------------------------------
// Utilities to make bitmasks human readable
func NewDefaultAccountPermissionsString() BasePermissionsString {
return BasePermissionsString{
Root: false,
Bond: true,
Send: true,
Call: true,
Name: true,
CreateAccount: true,
CreateContract: true,
}
}
func AccountPermissionsFromStrings(perms *BasePermissionsString, roles []string) (*AccountPermissions, error) {
base := NewBasePermissions()
permRv := reflect.ValueOf(perms)
for i := uint(0); i < uint(permRv.NumField()); i++ {
v := permRv.Field(int(i)).Bool()
base.Set(1<<i, v)
}
aP := &AccountPermissions{
Base: base,
Roles: make([]string, len(roles)),
}
copy(aP.Roles, roles)
return aP, nil
}
func AccountPermissionsToStrings(aP *AccountPermissions) (*BasePermissionsString, []string, error) {
perms := new(BasePermissionsString)
permsRv := reflect.ValueOf(perms).Elem()
for i := uint(0); i < NumBasePermissions; i++ {
pf := PermFlag(1 << i)
if aP.Base.IsSet(pf) {
// won't err if the bit is set
v, _ := aP.Base.Get(pf)
f := permsRv.Field(int(i))
f.SetBool(v)
}
}
roles := make([]string, len(aP.Roles))
copy(roles, aP.Roles)
return perms, roles, nil
}
func PermFlagToString(pf PermFlag) (perm string, err error) {
switch pf {
case Root:
perm = "root"
case Send:
perm = "send"
case Call:
perm = "call"
case CreateContract:
perm = "create_contract"
case CreateAccount:
perm = "create_account"
case Bond:
perm = "bond"
case Name:
perm = "name"
default:
err = fmt.Errorf("Unknown permission flag %b", pf)
}
return
}
func PermStringToFlag(perm string) (pf PermFlag, err error) {
switch perm {
case "root":
pf = Root
case "send":
pf = Send
case "call":
pf = Call
case "create_contract":
pf = CreateContract
case "create_account":
pf = CreateAccount
case "bond":
pf = Bond
case "name":
pf = Name
default:
err = fmt.Errorf("Unknown permission %s", perm)
}
return
}