package types import ( "fmt" . "github.com/tendermint/tendermint/common" ) //------------------------------------------------------------------------------------------------ var ( GlobalPermissionsAddress = Zero256[:20] GlobalPermissionsAddress256 = Zero256 ) // A particular permission type PermFlag uint64 // Base permission references are like unix (the index is already bit shifted) const ( // chain permissions Root PermFlag = 1 << iota // 1 Send // 2 Call // 4 CreateContract // 8 CreateAccount // 16 Bond // 32 Name // 64 // moderator permissions HasBase SetBase UnsetBase SetGlobal HasRole AddRole RmRole NumPermissions uint = 14 // NOTE Adjust this too. We can support upto 64 TopPermFlag PermFlag = 1 << (NumPermissions - 1) AllPermFlags PermFlag = TopPermFlag | (TopPermFlag - 1) DefaultPermFlags PermFlag = Send | Call | CreateContract | CreateAccount | Bond | Name | HasBase | HasRole ) var ( ZeroBasePermissions = BasePermissions{0, 0} ZeroAccountPermissions = AccountPermissions{ Base: ZeroBasePermissions, } DefaultAccountPermissions = AccountPermissions{ Base: BasePermissions{ Perms: DefaultPermFlags, SetBit: AllPermFlags, }, Roles: []string{}, } ) //--------------------------------------------------------------------------------------------- // 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"` } // 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) String() string { return fmt.Sprintf("Base: %b; Set: %b", p.Perms, p.SetBit) } //--------------------------------------------------------------------------------------------- type AccountPermissions struct { Base BasePermissions `json:"base"` Roles []string `json:"roles"` } // 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 } //-------------------------------------------------------------------------------- // string utilities // PermFlagToString assumes the permFlag is valid, else returns "#-UNKNOWN-#" func PermFlagToString(pf PermFlag) (perm string) { 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" case HasBase: perm = "has_base" case SetBase: perm = "set_base" case UnsetBase: perm = "unset_base" case SetGlobal: perm = "set_global" case HasRole: perm = "has_role" case AddRole: perm = "add_role" case RmRole: perm = "rm_role" default: perm = "#-UNKNOWN-#" } 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 case "has_base": pf = HasBase case "set_base": pf = SetBase case "unset_base": pf = UnsetBase case "set_global": pf = SetGlobal case "has_role": pf = HasRole case "add_role": pf = AddRole case "rm_role": pf = RmRole default: err = fmt.Errorf("Unknown permission %s", perm) } return }