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 }