github.com/aergoio/aergo@v1.3.1/contract/enterprise/validate.go (about)

     1  package enterprise
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"github.com/aergoio/aergo/consensus"
    10  	"strings"
    11  
    12  	"github.com/aergoio/aergo/state"
    13  	"github.com/aergoio/aergo/types"
    14  )
    15  
    16  const SetConf = "setConf"
    17  const AppendConf = "appendConf"
    18  const RemoveConf = "removeConf"
    19  const AppendAdmin = "appendAdmin"
    20  const RemoveAdmin = "removeAdmin"
    21  const EnableConf = "enableConf"
    22  const DisableConf = "disableConf"
    23  const ChangeCluster = "changeCluster"
    24  
    25  var ErrTxEnterpriseAdminIsNotSet = errors.New("admin is not set")
    26  
    27  func ValidateEnterpriseTx(tx *types.TxBody, sender *state.V,
    28  	scs *state.ContractState, blockNo types.BlockNo) (*EnterpriseContext, error) {
    29  	var ci types.CallInfo
    30  	if err := json.Unmarshal(tx.Payload, &ci); err != nil {
    31  		return nil, err
    32  	}
    33  	context := &EnterpriseContext{Call: &ci}
    34  	switch ci.Name {
    35  	case AppendAdmin, RemoveAdmin:
    36  		if len(ci.Args) != 1 { //args[0] : encoded admin address
    37  			return nil, fmt.Errorf("invalid arguments in payload for SetAdmin: %s", ci.Args)
    38  		}
    39  		arg := ci.Args[0].(string)
    40  		context.Args = append(context.Args, arg)
    41  
    42  		address := types.ToAddress(arg)
    43  		if len(address) == 0 {
    44  			return nil, fmt.Errorf("invalid arguments[0]: %s", ci.Args[0])
    45  		}
    46  		admins, err := checkAdmin(scs, sender.ID())
    47  		if err != nil &&
    48  			err != ErrTxEnterpriseAdminIsNotSet {
    49  			return nil, err
    50  		}
    51  		context.Admins = admins
    52  		if ci.Name == AppendAdmin && context.IsAdminExist(address) {
    53  			return nil, fmt.Errorf("already exist admin: %s", ci.Args[0])
    54  		} else if ci.Name == RemoveAdmin {
    55  			if !context.IsAdminExist(address) {
    56  				return nil, fmt.Errorf("admins is not exist : %s", ci.Args[0])
    57  			}
    58  			conf, err := getConf(scs, []byte(AccountWhite))
    59  			if err != nil {
    60  				return nil, err
    61  			}
    62  			if conf != nil && conf.On {
    63  				for _, v := range conf.Values {
    64  					if arg == v {
    65  						return nil, fmt.Errorf("admin is in the account whitelist: %s", ci.Args[0])
    66  					}
    67  				}
    68  			}
    69  		}
    70  
    71  	case SetConf:
    72  		if len(ci.Args) <= 1 { //args[0] : key, args[1:] : values
    73  			return nil, fmt.Errorf("invalid arguments in payload for setConf: %s", ci.Args)
    74  		}
    75  		if err := checkArgs(context, &ci); err != nil {
    76  			return nil, err
    77  		}
    78  		key := genKey([]byte(context.Args[0]))
    79  		admins, err := checkAdmin(scs, sender.ID())
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  		context.Admins = admins
    84  		if context.Conf, err = setConfValues(scs, key, context.Args[1:]); err != nil {
    85  			return nil, err
    86  		}
    87  
    88  	case AppendConf, RemoveConf:
    89  		if len(ci.Args) != 2 { //args[0] : key, args[1] : a value
    90  			return nil, fmt.Errorf("invalid arguments in payload for %s : %s", ci.Name, ci.Args)
    91  		}
    92  		if err := checkArgs(context, &ci); err != nil {
    93  			return nil, err
    94  		}
    95  		admins, err := checkAdmin(scs, sender.ID())
    96  		if err != nil {
    97  			return nil, err
    98  		}
    99  		conf, err := getConf(scs, []byte(context.Args[0]))
   100  		if err != nil {
   101  			return nil, err
   102  		}
   103  		if conf == nil {
   104  			conf = &Conf{On: false}
   105  		}
   106  		context.Conf = conf
   107  		context.Admins = admins
   108  
   109  		key := genKey([]byte(context.Args[0]))
   110  		if ci.Name == AppendConf {
   111  			if context.HasConfValue(context.Args[1]) {
   112  				return nil, fmt.Errorf("already included config value : %v", context.Args)
   113  			}
   114  			conf.AppendValue(context.Args[1])
   115  		} else if ci.Name == RemoveConf {
   116  			if !context.HasConfValue(context.Args[1]) {
   117  				return nil, fmt.Errorf("value not exist : %v", context.Args)
   118  			}
   119  			conf.RemoveValue(context.Args[1])
   120  		}
   121  
   122  		if err := conf.Validate(key, context); err != nil {
   123  			return nil, err
   124  		}
   125  
   126  	case EnableConf:
   127  		if len(ci.Args) != 2 { //args[0] : key, args[1] : true/false
   128  			return nil, fmt.Errorf("invalid arguments in payload for enableConf: %s", ci.Args)
   129  		}
   130  		arg0, ok := ci.Args[0].(string)
   131  		if !ok {
   132  			return nil, fmt.Errorf("not string in payload for enableConf : %s", ci.Args)
   133  		}
   134  		if _, ok := enterpriseKeyDict[strings.ToUpper(ci.Args[0].(string))]; !ok {
   135  			return nil, fmt.Errorf("not allowed key : %s", ci.Args[0])
   136  		}
   137  		context.Args = append(context.Args, arg0)
   138  		key := genKey([]byte(arg0))
   139  		value, ok := ci.Args[1].(bool)
   140  		if !ok {
   141  			return nil, fmt.Errorf("not bool in payload for enableConf : %s", ci.Args)
   142  		}
   143  		admins, err := checkAdmin(scs, sender.ID())
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  		conf, err := enableConf(scs, key, value)
   148  		if err != nil {
   149  			return nil, err
   150  		}
   151  
   152  		context.Admins = admins
   153  		context.Conf = conf
   154  
   155  		if err := conf.Validate(key, context); err != nil {
   156  			return nil, err
   157  		}
   158  
   159  	case ChangeCluster:
   160  		if !consensus.UseRaft() {
   161  			return nil, ErrNotSupportedMethod
   162  		}
   163  
   164  		cc, err := ValidateChangeCluster(ci, blockNo)
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  
   169  		context.ArgsAny = append(context.ArgsAny, cc)
   170  
   171  		admins, err := checkAdmin(scs, sender.ID())
   172  		if err != nil {
   173  			return nil, err
   174  		}
   175  		context.Admins = admins
   176  	default:
   177  		return nil, fmt.Errorf("unsupported call %s", ci.Name)
   178  	}
   179  	return context, nil
   180  }
   181  
   182  func checkAdmin(scs *state.ContractState, address []byte) ([][]byte, error) {
   183  	admins, err := getAdmins(scs)
   184  	if err != nil {
   185  		return nil, fmt.Errorf("could not get admin in enterprise contract")
   186  	}
   187  	if admins == nil {
   188  		return nil, ErrTxEnterpriseAdminIsNotSet
   189  	}
   190  	if i := bytes.Index(bytes.Join(admins, []byte("")), address); i == -1 && i%types.AddressLength != 0 {
   191  		return nil, fmt.Errorf("admin address not matched")
   192  	}
   193  	return admins, nil
   194  }
   195  
   196  type checkArgsFunc func(string) error
   197  
   198  func checkArgs(context *EnterpriseContext, ci *types.CallInfo) error {
   199  	key := strings.ToUpper(ci.Args[0].(string))
   200  	if _, ok := enterpriseKeyDict[key]; !ok {
   201  		return fmt.Errorf("not allowed key : %s", ci.Args[0])
   202  	}
   203  
   204  	unique := map[string]int{}
   205  	var op checkArgsFunc
   206  	switch key {
   207  	case P2PWhite, P2PBlack:
   208  		op = checkP2PBlackWhite
   209  	case AccountWhite:
   210  		op = checkAccountWhite
   211  	case RPCPermissions:
   212  		op = checkRPCPermissions
   213  	default:
   214  		op = checkNone
   215  	}
   216  
   217  	for i, v := range ci.Args {
   218  		arg, ok := v.(string)
   219  		if !ok {
   220  			return fmt.Errorf("not string in payload for setting conf : %s", ci.Args)
   221  		}
   222  		if strings.Contains(arg, "\\") {
   223  			return fmt.Errorf("not allowed charactor in %s", arg)
   224  		}
   225  		if unique[arg] != 0 {
   226  			return fmt.Errorf("the request has duplicate arguments %s", arg)
   227  		}
   228  		unique[arg]++
   229  		context.Args = append(context.Args, arg)
   230  		if i == 0 { //it's key
   231  			continue
   232  		}
   233  		if err := op(arg); err != nil {
   234  			return err
   235  		}
   236  	}
   237  
   238  	return nil
   239  }
   240  
   241  func checkP2PBlackWhite(v string) error {
   242  	// v must be json object. e.g. {"peerid":"16Uiu2HAmPZE7gT1hF2bjpg1UVH65xyNUbBVRf3mBFBJpz3tgLGGt", "address":"", "cidr":"172.21.3.35/24" } , which address and cidr cannot be set in same time.
   243  	if _, err := types.ParseListEntry(v); err != nil {
   244  		return fmt.Errorf("invalid p2p whitelist %s", v)
   245  	}
   246  	return nil
   247  }
   248  
   249  func checkAccountWhite(v string) error {
   250  	if _, err := types.DecodeAddress(v); err != nil {
   251  		return fmt.Errorf("invalid account %s", v)
   252  	}
   253  	return nil
   254  }
   255  
   256  func checkRPCPermissions(v string) error {
   257  	values := strings.Split(v, ":")
   258  	if len(values) != 2 {
   259  		return fmt.Errorf("invalid RPC permission %s", v)
   260  	}
   261  
   262  	if _, err := base64.StdEncoding.DecodeString(values[0]); err != nil {
   263  		return fmt.Errorf("invalid RPC cert %s", v)
   264  	}
   265  
   266  	return nil
   267  }
   268  
   269  func checkNone(v string) error {
   270  	return nil
   271  }