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<