github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/signer/core/signed_data.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "bytes" 21 "context" 22 "errors" 23 "fmt" 24 "math/big" 25 "mime" 26 "reflect" 27 "regexp" 28 "sort" 29 "strconv" 30 "strings" 31 "unicode" 32 "unicode/utf8" 33 34 "github.com/ethereum/go-ethereum/accounts" 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/common/hexutil" 37 "github.com/ethereum/go-ethereum/common/math" 38 "github.com/ethereum/go-ethereum/consensus/clique" 39 "github.com/ethereum/go-ethereum/core/types" 40 "github.com/ethereum/go-ethereum/crypto" 41 "github.com/ethereum/go-ethereum/rlp" 42 "github.com/ethereum/go-ethereum/signer/core/apitypes" 43 ) 44 45 type SigFormat struct { 46 Mime string 47 ByteVersion byte 48 } 49 50 var ( 51 IntendedValidator = SigFormat{ 52 accounts.MimetypeDataWithValidator, 53 0x00, 54 } 55 DataTyped = SigFormat{ 56 accounts.MimetypeTypedData, 57 0x01, 58 } 59 ApplicationClique = SigFormat{ 60 accounts.MimetypeClique, 61 0x02, 62 } 63 ApplicationBor = SigFormat{ 64 accounts.MimetypeBor, 65 0x10, 66 } 67 TextPlain = SigFormat{ 68 accounts.MimetypeTextPlain, 69 0x45, 70 } 71 ) 72 73 type ValidatorData struct { 74 Address common.Address 75 Message hexutil.Bytes 76 } 77 78 type TypedData struct { 79 Types Types `json:"types"` 80 PrimaryType string `json:"primaryType"` 81 Domain TypedDataDomain `json:"domain"` 82 Message TypedDataMessage `json:"message"` 83 } 84 85 type Type struct { 86 Name string `json:"name"` 87 Type string `json:"type"` 88 } 89 90 func (t *Type) isArray() bool { 91 return strings.HasSuffix(t.Type, "[]") 92 } 93 94 // typeName returns the canonical name of the type. If the type is 'Person[]', then 95 // this method returns 'Person' 96 func (t *Type) typeName() string { 97 if strings.HasSuffix(t.Type, "[]") { 98 return strings.TrimSuffix(t.Type, "[]") 99 } 100 return t.Type 101 } 102 103 func (t *Type) isReferenceType() bool { 104 if len(t.Type) == 0 { 105 return false 106 } 107 // Reference types must have a leading uppercase character 108 r, _ := utf8.DecodeRuneInString(t.Type) 109 return unicode.IsUpper(r) 110 } 111 112 type Types map[string][]Type 113 114 type TypePriority struct { 115 Type string 116 Value uint 117 } 118 119 type TypedDataMessage = map[string]interface{} 120 121 type TypedDataDomain struct { 122 Name string `json:"name"` 123 Version string `json:"version"` 124 ChainId *math.HexOrDecimal256 `json:"chainId"` 125 VerifyingContract string `json:"verifyingContract"` 126 Salt string `json:"salt"` 127 } 128 129 var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Z](\w*)(\[\])?$`) 130 131 // sign receives a request and produces a signature 132 // 133 // Note, the produced signature conforms to the secp256k1 curve R, S and V values, 134 // where the V value will be 27 or 28 for legacy reasons, if legacyV==true. 135 func (api *SignerAPI) sign(req *SignDataRequest, legacyV bool) (hexutil.Bytes, error) { 136 // We make the request prior to looking up if we actually have the account, to prevent 137 // account-enumeration via the API 138 res, err := api.UI.ApproveSignData(req) 139 if err != nil { 140 return nil, err 141 } 142 if !res.Approved { 143 return nil, ErrRequestDenied 144 } 145 // Look up the wallet containing the requested signer 146 account := accounts.Account{Address: req.Address.Address()} 147 wallet, err := api.am.Find(account) 148 if err != nil { 149 return nil, err 150 } 151 pw, err := api.lookupOrQueryPassword(account.Address, 152 "Password for signing", 153 fmt.Sprintf("Please enter password for signing data with account %s", account.Address.Hex())) 154 if err != nil { 155 return nil, err 156 } 157 // Sign the data with the wallet 158 signature, err := wallet.SignDataWithPassphrase(account, pw, req.ContentType, req.Rawdata) 159 if err != nil { 160 return nil, err 161 } 162 if legacyV { 163 signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 164 } 165 return signature, nil 166 } 167 168 // SignData signs the hash of the provided data, but does so differently 169 // depending on the content-type specified. 170 // 171 // Different types of validation occur. 172 func (api *SignerAPI) SignData(ctx context.Context, contentType string, addr common.MixedcaseAddress, data interface{}) (hexutil.Bytes, error) { 173 var req, transformV, err = api.determineSignatureFormat(ctx, contentType, addr, data) 174 if err != nil { 175 return nil, err 176 } 177 signature, err := api.sign(req, transformV) 178 if err != nil { 179 api.UI.ShowError(err.Error()) 180 return nil, err 181 } 182 return signature, nil 183 } 184 185 // determineSignatureFormat determines which signature method should be used based upon the mime type 186 // In the cases where it matters ensure that the charset is handled. The charset 187 // resides in the 'params' returned as the second returnvalue from mime.ParseMediaType 188 // charset, ok := params["charset"] 189 // As it is now, we accept any charset and just treat it as 'raw'. 190 // This method returns the mimetype for signing along with the request 191 func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType string, addr common.MixedcaseAddress, data interface{}) (*SignDataRequest, bool, error) { 192 var ( 193 req *SignDataRequest 194 useEthereumV = true // Default to use V = 27 or 28, the legacy Ethereum format 195 ) 196 mediaType, _, err := mime.ParseMediaType(contentType) 197 if err != nil { 198 return nil, useEthereumV, err 199 } 200 201 switch mediaType { 202 case IntendedValidator.Mime: 203 // Data with an intended validator 204 validatorData, err := UnmarshalValidatorData(data) 205 if err != nil { 206 return nil, useEthereumV, err 207 } 208 sighash, msg := SignTextValidator(validatorData) 209 messages := []*NameValueType{ 210 { 211 Name: "This is a request to sign data intended for a particular validator (see EIP 191 version 0)", 212 Typ: "description", 213 Value: "", 214 }, 215 { 216 Name: "Intended validator address", 217 Typ: "address", 218 Value: validatorData.Address.String(), 219 }, 220 { 221 Name: "Application-specific data", 222 Typ: "hexdata", 223 Value: validatorData.Message, 224 }, 225 { 226 Name: "Full message for signing", 227 Typ: "hexdata", 228 Value: fmt.Sprintf("0x%x", msg), 229 }, 230 } 231 req = &SignDataRequest{ContentType: mediaType, Rawdata: []byte(msg), Messages: messages, Hash: sighash} 232 case ApplicationClique.Mime: 233 // Clique is the Ethereum PoA standard 234 stringData, ok := data.(string) 235 if !ok { 236 return nil, useEthereumV, fmt.Errorf("input for %v must be an hex-encoded string", ApplicationClique.Mime) 237 } 238 cliqueData, err := hexutil.Decode(stringData) 239 if err != nil { 240 return nil, useEthereumV, err 241 } 242 header := &types.Header{} 243 if err := rlp.DecodeBytes(cliqueData, header); err != nil { 244 return nil, useEthereumV, err 245 } 246 // The incoming clique header is already truncated, sent to us with a extradata already shortened 247 if len(header.Extra) < 65 { 248 // Need to add it back, to get a suitable length for hashing 249 newExtra := make([]byte, len(header.Extra)+65) 250 copy(newExtra, header.Extra) 251 header.Extra = newExtra 252 } 253 // Get back the rlp data, encoded by us 254 sighash, cliqueRlp, err := cliqueHeaderHashAndRlp(header) 255 if err != nil { 256 return nil, useEthereumV, err 257 } 258 messages := []*NameValueType{ 259 { 260 Name: "Clique header", 261 Typ: "clique", 262 Value: fmt.Sprintf("clique header %d [0x%x]", header.Number, header.Hash()), 263 }, 264 } 265 // Clique uses V on the form 0 or 1 266 useEthereumV = false 267 req = &SignDataRequest{ContentType: mediaType, Rawdata: cliqueRlp, Messages: messages, Hash: sighash} 268 default: // also case TextPlain.Mime: 269 // Calculates an Ethereum ECDSA signature for: 270 // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") 271 // We expect it to be a string 272 if stringData, ok := data.(string); !ok { 273 return nil, useEthereumV, fmt.Errorf("input for text/plain must be an hex-encoded string") 274 } else { 275 if textData, err := hexutil.Decode(stringData); err != nil { 276 return nil, useEthereumV, err 277 } else { 278 sighash, msg := accounts.TextAndHash(textData) 279 messages := []*NameValueType{ 280 { 281 Name: "message", 282 Typ: accounts.MimetypeTextPlain, 283 Value: msg, 284 }, 285 } 286 req = &SignDataRequest{ContentType: mediaType, Rawdata: []byte(msg), Messages: messages, Hash: sighash} 287 } 288 } 289 } 290 req.Address = addr 291 req.Meta = MetadataFromContext(ctx) 292 return req, useEthereumV, nil 293 } 294 295 // SignTextWithValidator signs the given message which can be further recovered 296 // with the given validator. 297 // hash = keccak256("\x19\x00"${address}${data}). 298 func SignTextValidator(validatorData ValidatorData) (hexutil.Bytes, string) { 299 msg := fmt.Sprintf("\x19\x00%s%s", string(validatorData.Address.Bytes()), string(validatorData.Message)) 300 return crypto.Keccak256([]byte(msg)), msg 301 } 302 303 // cliqueHeaderHashAndRlp returns the hash which is used as input for the proof-of-authority 304 // signing. It is the hash of the entire header apart from the 65 byte signature 305 // contained at the end of the extra data. 306 // 307 // The method requires the extra data to be at least 65 bytes -- the original implementation 308 // in clique.go panics if this is the case, thus it's been reimplemented here to avoid the panic 309 // and simply return an error instead 310 func cliqueHeaderHashAndRlp(header *types.Header) (hash, rlp []byte, err error) { 311 if len(header.Extra) < 65 { 312 err = fmt.Errorf("clique header extradata too short, %d < 65", len(header.Extra)) 313 return 314 } 315 rlp = clique.CliqueRLP(header) 316 hash = clique.SealHash(header).Bytes() 317 return hash, rlp, err 318 } 319 320 // SignTypedData signs EIP-712 conformant typed data 321 // hash = keccak256("\x19${byteVersion}${domainSeparator}${hashStruct(message)}") 322 // It returns 323 // - the signature, 324 // - and/or any error 325 func (api *SignerAPI) SignTypedData(ctx context.Context, addr common.MixedcaseAddress, typedData TypedData) (hexutil.Bytes, error) { 326 signature, _, err := api.signTypedData(ctx, addr, typedData, nil) 327 return signature, err 328 } 329 330 // signTypedData is identical to the capitalized version, except that it also returns the hash (preimage) 331 // - the signature preimage (hash) 332 func (api *SignerAPI) signTypedData(ctx context.Context, addr common.MixedcaseAddress, 333 typedData TypedData, validationMessages *apitypes.ValidationMessages) (hexutil.Bytes, hexutil.Bytes, error) { 334 domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) 335 if err != nil { 336 return nil, nil, err 337 } 338 typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) 339 if err != nil { 340 return nil, nil, err 341 } 342 rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) 343 sighash := crypto.Keccak256(rawData) 344 messages, err := typedData.Format() 345 if err != nil { 346 return nil, nil, err 347 } 348 req := &SignDataRequest{ 349 ContentType: DataTyped.Mime, 350 Rawdata: rawData, 351 Messages: messages, 352 Hash: sighash, 353 Address: addr} 354 if validationMessages != nil { 355 req.Callinfo = validationMessages.Messages 356 } 357 signature, err := api.sign(req, true) 358 if err != nil { 359 api.UI.ShowError(err.Error()) 360 return nil, nil, err 361 } 362 return signature, sighash, nil 363 } 364 365 // HashStruct generates a keccak256 hash of the encoding of the provided data 366 func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage) (hexutil.Bytes, error) { 367 encodedData, err := typedData.EncodeData(primaryType, data, 1) 368 if err != nil { 369 return nil, err 370 } 371 return crypto.Keccak256(encodedData), nil 372 } 373 374 // Dependencies returns an array of custom types ordered by their hierarchical reference tree 375 func (typedData *TypedData) Dependencies(primaryType string, found []string) []string { 376 includes := func(arr []string, str string) bool { 377 for _, obj := range arr { 378 if obj == str { 379 return true 380 } 381 } 382 return false 383 } 384 385 if includes(found, primaryType) { 386 return found 387 } 388 if typedData.Types[primaryType] == nil { 389 return found 390 } 391 found = append(found, primaryType) 392 for _, field := range typedData.Types[primaryType] { 393 for _, dep := range typedData.Dependencies(field.Type, found) { 394 if !includes(found, dep) { 395 found = append(found, dep) 396 } 397 } 398 } 399 return found 400 } 401 402 // EncodeType generates the following encoding: 403 // `name ‖ "(" ‖ member₁ ‖ "," ‖ member₂ ‖ "," ‖ … ‖ memberₙ ")"` 404 // 405 // each member is written as `type ‖ " " ‖ name` encodings cascade down and are sorted by name 406 func (typedData *TypedData) EncodeType(primaryType string) hexutil.Bytes { 407 // Get dependencies primary first, then alphabetical 408 deps := typedData.Dependencies(primaryType, []string{}) 409 if len(deps) > 0 { 410 slicedDeps := deps[1:] 411 sort.Strings(slicedDeps) 412 deps = append([]string{primaryType}, slicedDeps...) 413 } 414 415 // Format as a string with fields 416 var buffer bytes.Buffer 417 for _, dep := range deps { 418 buffer.WriteString(dep) 419 buffer.WriteString("(") 420 for _, obj := range typedData.Types[dep] { 421 buffer.WriteString(obj.Type) 422 buffer.WriteString(" ") 423 buffer.WriteString(obj.Name) 424 buffer.WriteString(",") 425 } 426 buffer.Truncate(buffer.Len() - 1) 427 buffer.WriteString(")") 428 } 429 return buffer.Bytes() 430 } 431 432 // TypeHash creates the keccak256 hash of the data 433 func (typedData *TypedData) TypeHash(primaryType string) hexutil.Bytes { 434 return crypto.Keccak256(typedData.EncodeType(primaryType)) 435 } 436 437 // EncodeData generates the following encoding: 438 // `enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ)` 439 // 440 // each encoded member is 32-byte long 441 func (typedData *TypedData) EncodeData(primaryType string, data map[string]interface{}, depth int) (hexutil.Bytes, error) { 442 if err := typedData.validate(); err != nil { 443 return nil, err 444 } 445 446 buffer := bytes.Buffer{} 447 448 // Verify extra data 449 if exp, got := len(typedData.Types[primaryType]), len(data); exp < got { 450 return nil, fmt.Errorf("there is extra data provided in the message (%d < %d)", exp, got) 451 } 452 453 // Add typehash 454 buffer.Write(typedData.TypeHash(primaryType)) 455 456 // Add field contents. Structs and arrays have special handlers. 457 for _, field := range typedData.Types[primaryType] { 458 encType := field.Type 459 encValue := data[field.Name] 460 if encType[len(encType)-1:] == "]" { 461 arrayValue, ok := encValue.([]interface{}) 462 if !ok { 463 return nil, dataMismatchError(encType, encValue) 464 } 465 466 arrayBuffer := bytes.Buffer{} 467 parsedType := strings.Split(encType, "[")[0] 468 for _, item := range arrayValue { 469 if typedData.Types[parsedType] != nil { 470 mapValue, ok := item.(map[string]interface{}) 471 if !ok { 472 return nil, dataMismatchError(parsedType, item) 473 } 474 encodedData, err := typedData.EncodeData(parsedType, mapValue, depth+1) 475 if err != nil { 476 return nil, err 477 } 478 arrayBuffer.Write(encodedData) 479 } else { 480 bytesValue, err := typedData.EncodePrimitiveValue(parsedType, item, depth) 481 if err != nil { 482 return nil, err 483 } 484 arrayBuffer.Write(bytesValue) 485 } 486 } 487 488 buffer.Write(crypto.Keccak256(arrayBuffer.Bytes())) 489 } else if typedData.Types[field.Type] != nil { 490 mapValue, ok := encValue.(map[string]interface{}) 491 if !ok { 492 return nil, dataMismatchError(encType, encValue) 493 } 494 encodedData, err := typedData.EncodeData(field.Type, mapValue, depth+1) 495 if err != nil { 496 return nil, err 497 } 498 buffer.Write(crypto.Keccak256(encodedData)) 499 } else { 500 byteValue, err := typedData.EncodePrimitiveValue(encType, encValue, depth) 501 if err != nil { 502 return nil, err 503 } 504 buffer.Write(byteValue) 505 } 506 } 507 return buffer.Bytes(), nil 508 } 509 510 // Attempt to parse bytes in different formats: byte array, hex string, hexutil.Bytes. 511 func parseBytes(encType interface{}) ([]byte, bool) { 512 switch v := encType.(type) { 513 case []byte: 514 return v, true 515 case hexutil.Bytes: 516 return v, true 517 case string: 518 bytes, err := hexutil.Decode(v) 519 if err != nil { 520 return nil, false 521 } 522 return bytes, true 523 default: 524 return nil, false 525 } 526 } 527 528 func parseInteger(encType string, encValue interface{}) (*big.Int, error) { 529 var ( 530 length int 531 signed = strings.HasPrefix(encType, "int") 532 b *big.Int 533 ) 534 if encType == "int" || encType == "uint" { 535 length = 256 536 } else { 537 lengthStr := "" 538 if strings.HasPrefix(encType, "uint") { 539 lengthStr = strings.TrimPrefix(encType, "uint") 540 } else { 541 lengthStr = strings.TrimPrefix(encType, "int") 542 } 543 atoiSize, err := strconv.Atoi(lengthStr) 544 if err != nil { 545 return nil, fmt.Errorf("invalid size on integer: %v", lengthStr) 546 } 547 length = atoiSize 548 } 549 switch v := encValue.(type) { 550 case *math.HexOrDecimal256: 551 b = (*big.Int)(v) 552 case string: 553 var hexIntValue math.HexOrDecimal256 554 if err := hexIntValue.UnmarshalText([]byte(v)); err != nil { 555 return nil, err 556 } 557 b = (*big.Int)(&hexIntValue) 558 case float64: 559 // JSON parses non-strings as float64. Fail if we cannot 560 // convert it losslessly 561 if float64(int64(v)) == v { 562 b = big.NewInt(int64(v)) 563 } else { 564 return nil, fmt.Errorf("invalid float value %v for type %v", v, encType) 565 } 566 } 567 if b == nil { 568 return nil, fmt.Errorf("invalid integer value %v/%v for type %v", encValue, reflect.TypeOf(encValue), encType) 569 } 570 if b.BitLen() > length { 571 return nil, fmt.Errorf("integer larger than '%v'", encType) 572 } 573 if !signed && b.Sign() == -1 { 574 return nil, fmt.Errorf("invalid negative value for unsigned type %v", encType) 575 } 576 return b, nil 577 } 578 579 // EncodePrimitiveValue deals with the primitive values found 580 // while searching through the typed data 581 func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interface{}, depth int) ([]byte, error) { 582 switch encType { 583 case "address": 584 stringValue, ok := encValue.(string) 585 if !ok || !common.IsHexAddress(stringValue) { 586 return nil, dataMismatchError(encType, encValue) 587 } 588 retval := make([]byte, 32) 589 copy(retval[12:], common.HexToAddress(stringValue).Bytes()) 590 return retval, nil 591 case "bool": 592 boolValue, ok := encValue.(bool) 593 if !ok { 594 return nil, dataMismatchError(encType, encValue) 595 } 596 if boolValue { 597 return math.PaddedBigBytes(common.Big1, 32), nil 598 } 599 return math.PaddedBigBytes(common.Big0, 32), nil 600 case "string": 601 strVal, ok := encValue.(string) 602 if !ok { 603 return nil, dataMismatchError(encType, encValue) 604 } 605 return crypto.Keccak256([]byte(strVal)), nil 606 case "bytes": 607 bytesValue, ok := parseBytes(encValue) 608 if !ok { 609 return nil, dataMismatchError(encType, encValue) 610 } 611 return crypto.Keccak256(bytesValue), nil 612 } 613 if strings.HasPrefix(encType, "bytes") { 614 lengthStr := strings.TrimPrefix(encType, "bytes") 615 length, err := strconv.Atoi(lengthStr) 616 if err != nil { 617 return nil, fmt.Errorf("invalid size on bytes: %v", lengthStr) 618 } 619 if length < 0 || length > 32 { 620 return nil, fmt.Errorf("invalid size on bytes: %d", length) 621 } 622 if byteValue, ok := parseBytes(encValue); !ok || len(byteValue) != length { 623 return nil, dataMismatchError(encType, encValue) 624 } else { 625 // Right-pad the bits 626 dst := make([]byte, 32) 627 copy(dst, byteValue) 628 return dst, nil 629 } 630 } 631 if strings.HasPrefix(encType, "int") || strings.HasPrefix(encType, "uint") { 632 b, err := parseInteger(encType, encValue) 633 if err != nil { 634 return nil, err 635 } 636 return math.U256Bytes(b), nil 637 } 638 return nil, fmt.Errorf("unrecognized type '%s'", encType) 639 640 } 641 642 // dataMismatchError generates an error for a mismatch between 643 // the provided type and data 644 func dataMismatchError(encType string, encValue interface{}) error { 645 return fmt.Errorf("provided data '%v' doesn't match type '%s'", encValue, encType) 646 } 647 648 // EcRecover recovers the address associated with the given sig. 649 // Only compatible with `text/plain` 650 func (api *SignerAPI) EcRecover(ctx context.Context, data hexutil.Bytes, sig hexutil.Bytes) (common.Address, error) { 651 // Returns the address for the Account that was used to create the signature. 652 // 653 // Note, this function is compatible with eth_sign and personal_sign. As such it recovers 654 // the address of: 655 // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") 656 // addr = ecrecover(hash, signature) 657 // 658 // Note, the signature must conform to the secp256k1 curve R, S and V values, where 659 // the V value must be be 27 or 28 for legacy reasons. 660 // 661 // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover 662 if len(sig) != 65 { 663 return common.Address{}, fmt.Errorf("signature must be 65 bytes long") 664 } 665 if sig[64] != 27 && sig[64] != 28 { 666 return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)") 667 } 668 sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1 669 hash := accounts.TextHash(data) 670 rpk, err := crypto.SigToPub(hash, sig) 671 if err != nil { 672 return common.Address{}, err 673 } 674 return crypto.PubkeyToAddress(*rpk), nil 675 } 676 677 // UnmarshalValidatorData converts the bytes input to typed data 678 func UnmarshalValidatorData(data interface{}) (ValidatorData, error) { 679 raw, ok := data.(map[string]interface{}) 680 if !ok { 681 return ValidatorData{}, errors.New("validator input is not a map[string]interface{}") 682 } 683 addr, ok := raw["address"].(string) 684 if !ok { 685 return ValidatorData{}, errors.New("validator address is not sent as a string") 686 } 687 addrBytes, err := hexutil.Decode(addr) 688 if err != nil { 689 return ValidatorData{}, err 690 } 691 if !ok || len(addrBytes) == 0 { 692 return ValidatorData{}, errors.New("validator address is undefined") 693 } 694 695 message, ok := raw["message"].(string) 696 if !ok { 697 return ValidatorData{}, errors.New("message is not sent as a string") 698 } 699 messageBytes, err := hexutil.Decode(message) 700 if err != nil { 701 return ValidatorData{}, err 702 } 703 if !ok || len(messageBytes) == 0 { 704 return ValidatorData{}, errors.New("message is undefined") 705 } 706 707 return ValidatorData{ 708 Address: common.BytesToAddress(addrBytes), 709 Message: messageBytes, 710 }, nil 711 } 712 713 // validate makes sure the types are sound 714 func (typedData *TypedData) validate() error { 715 if err := typedData.Types.validate(); err != nil { 716 return err 717 } 718 if err := typedData.Domain.validate(); err != nil { 719 return err 720 } 721 return nil 722 } 723 724 // Map generates a map version of the typed data 725 func (typedData *TypedData) Map() map[string]interface{} { 726 dataMap := map[string]interface{}{ 727 "types": typedData.Types, 728 "domain": typedData.Domain.Map(), 729 "primaryType": typedData.PrimaryType, 730 "message": typedData.Message, 731 } 732 return dataMap 733 } 734 735 // Format returns a representation of typedData, which can be easily displayed by a user-interface 736 // without in-depth knowledge about 712 rules 737 func (typedData *TypedData) Format() ([]*NameValueType, error) { 738 domain, err := typedData.formatData("EIP712Domain", typedData.Domain.Map()) 739 if err != nil { 740 return nil, err 741 } 742 ptype, err := typedData.formatData(typedData.PrimaryType, typedData.Message) 743 if err != nil { 744 return nil, err 745 } 746 var nvts []*NameValueType 747 nvts = append(nvts, &NameValueType{ 748 Name: "EIP712Domain", 749 Value: domain, 750 Typ: "domain", 751 }) 752 nvts = append(nvts, &NameValueType{ 753 Name: typedData.PrimaryType, 754 Value: ptype, 755 Typ: "primary type", 756 }) 757 return nvts, nil 758 } 759 760 func (typedData *TypedData) formatData(primaryType string, data map[string]interface{}) ([]*NameValueType, error) { 761 var output []*NameValueType 762 763 // Add field contents. Structs and arrays have special handlers. 764 for _, field := range typedData.Types[primaryType] { 765 encName := field.Name 766 encValue := data[encName] 767 item := &NameValueType{ 768 Name: encName, 769 Typ: field.Type, 770 } 771 if field.isArray() { 772 arrayValue, _ := encValue.([]interface{}) 773 parsedType := field.typeName() 774 for _, v := range arrayValue { 775 if typedData.Types[parsedType] != nil { 776 mapValue, _ := v.(map[string]interface{}) 777 mapOutput, err := typedData.formatData(parsedType, mapValue) 778 if err != nil { 779 return nil, err 780 } 781 item.Value = mapOutput 782 } else { 783 primitiveOutput, err := formatPrimitiveValue(field.Type, encValue) 784 if err != nil { 785 return nil, err 786 } 787 item.Value = primitiveOutput 788 } 789 } 790 } else if typedData.Types[field.Type] != nil { 791 if mapValue, ok := encValue.(map[string]interface{}); ok { 792 mapOutput, err := typedData.formatData(field.Type, mapValue) 793 if err != nil { 794 return nil, err 795 } 796 item.Value = mapOutput 797 } else { 798 item.Value = "<nil>" 799 } 800 } else { 801 primitiveOutput, err := formatPrimitiveValue(field.Type, encValue) 802 if err != nil { 803 return nil, err 804 } 805 item.Value = primitiveOutput 806 } 807 output = append(output, item) 808 } 809 return output, nil 810 } 811 812 func formatPrimitiveValue(encType string, encValue interface{}) (string, error) { 813 switch encType { 814 case "address": 815 if stringValue, ok := encValue.(string); !ok { 816 return "", fmt.Errorf("could not format value %v as address", encValue) 817 } else { 818 return common.HexToAddress(stringValue).String(), nil 819 } 820 case "bool": 821 if boolValue, ok := encValue.(bool); !ok { 822 return "", fmt.Errorf("could not format value %v as bool", encValue) 823 } else { 824 return fmt.Sprintf("%t", boolValue), nil 825 } 826 case "bytes", "string": 827 return fmt.Sprintf("%s", encValue), nil 828 } 829 if strings.HasPrefix(encType, "bytes") { 830 return fmt.Sprintf("%s", encValue), nil 831 832 } 833 if strings.HasPrefix(encType, "uint") || strings.HasPrefix(encType, "int") { 834 if b, err := parseInteger(encType, encValue); err != nil { 835 return "", err 836 } else { 837 return fmt.Sprintf("%d (0x%x)", b, b), nil 838 } 839 } 840 return "", fmt.Errorf("unhandled type %v", encType) 841 } 842 843 // NameValueType is a very simple struct with Name, Value and Type. It's meant for simple 844 // json structures used to communicate signing-info about typed data with the UI 845 type NameValueType struct { 846 Name string `json:"name"` 847 Value interface{} `json:"value"` 848 Typ string `json:"type"` 849 } 850 851 // Pprint returns a pretty-printed version of nvt 852 func (nvt *NameValueType) Pprint(depth int) string { 853 output := bytes.Buffer{} 854 output.WriteString(strings.Repeat("\u00a0", depth*2)) 855 output.WriteString(fmt.Sprintf("%s [%s]: ", nvt.Name, nvt.Typ)) 856 if nvts, ok := nvt.Value.([]*NameValueType); ok { 857 output.WriteString("\n") 858 for _, next := range nvts { 859 sublevel := next.Pprint(depth + 1) 860 output.WriteString(sublevel) 861 } 862 } else { 863 if nvt.Value != nil { 864 output.WriteString(fmt.Sprintf("%q\n", nvt.Value)) 865 } else { 866 output.WriteString("\n") 867 } 868 } 869 return output.String() 870 } 871 872 // Validate checks if the types object is conformant to the specs 873 func (t Types) validate() error { 874 for typeKey, typeArr := range t { 875 if len(typeKey) == 0 { 876 return fmt.Errorf("empty type key") 877 } 878 for i, typeObj := range typeArr { 879 if len(typeObj.Type) == 0 { 880 return fmt.Errorf("type %q:%d: empty Type", typeKey, i) 881 } 882 if len(typeObj.Name) == 0 { 883 return fmt.Errorf("type %q:%d: empty Name", typeKey, i) 884 } 885 if typeKey == typeObj.Type { 886 return fmt.Errorf("type %q cannot reference itself", typeObj.Type) 887 } 888 if typeObj.isReferenceType() { 889 if _, exist := t[typeObj.typeName()]; !exist { 890 return fmt.Errorf("reference type %q is undefined", typeObj.Type) 891 } 892 if !typedDataReferenceTypeRegexp.MatchString(typeObj.Type) { 893 return fmt.Errorf("unknown reference type %q", typeObj.Type) 894 } 895 } else if !isPrimitiveTypeValid(typeObj.Type) { 896 return fmt.Errorf("unknown type %q", typeObj.Type) 897 } 898 } 899 } 900 return nil 901 } 902 903 // Checks if the primitive value is valid 904 func isPrimitiveTypeValid(primitiveType string) bool { 905 if primitiveType == "address" || 906 primitiveType == "address[]" || 907 primitiveType == "bool" || 908 primitiveType == "bool[]" || 909 primitiveType == "string" || 910 primitiveType == "string[]" { 911 return true 912 } 913 if primitiveType == "bytes" || 914 primitiveType == "bytes[]" || 915 primitiveType == "bytes1" || 916 primitiveType == "bytes1[]" || 917 primitiveType == "bytes2" || 918 primitiveType == "bytes2[]" || 919 primitiveType == "bytes3" || 920 primitiveType == "bytes3[]" || 921 primitiveType == "bytes4" || 922 primitiveType == "bytes4[]" || 923 primitiveType == "bytes5" || 924 primitiveType == "bytes5[]" || 925 primitiveType == "bytes6" || 926 primitiveType == "bytes6[]" || 927 primitiveType == "bytes7" || 928 primitiveType == "bytes7[]" || 929 primitiveType == "bytes8" || 930 primitiveType == "bytes8[]" || 931 primitiveType == "bytes9" || 932 primitiveType == "bytes9[]" || 933 primitiveType == "bytes10" || 934 primitiveType == "bytes10[]" || 935 primitiveType == "bytes11" || 936 primitiveType == "bytes11[]" || 937 primitiveType == "bytes12" || 938 primitiveType == "bytes12[]" || 939 primitiveType == "bytes13" || 940 primitiveType == "bytes13[]" || 941 primitiveType == "bytes14" || 942 primitiveType == "bytes14[]" || 943 primitiveType == "bytes15" || 944 primitiveType == "bytes15[]" || 945 primitiveType == "bytes16" || 946 primitiveType == "bytes16[]" || 947 primitiveType == "bytes17" || 948 primitiveType == "bytes17[]" || 949 primitiveType == "bytes18" || 950 primitiveType == "bytes18[]" || 951 primitiveType == "bytes19" || 952 primitiveType == "bytes19[]" || 953 primitiveType == "bytes20" || 954 primitiveType == "bytes20[]" || 955 primitiveType == "bytes21" || 956 primitiveType == "bytes21[]" || 957 primitiveType == "bytes22" || 958 primitiveType == "bytes22[]" || 959 primitiveType == "bytes23" || 960 primitiveType == "bytes23[]" || 961 primitiveType == "bytes24" || 962 primitiveType == "bytes24[]" || 963 primitiveType == "bytes25" || 964 primitiveType == "bytes25[]" || 965 primitiveType == "bytes26" || 966 primitiveType == "bytes26[]" || 967 primitiveType == "bytes27" || 968 primitiveType == "bytes27[]" || 969 primitiveType == "bytes28" || 970 primitiveType == "bytes28[]" || 971 primitiveType == "bytes29" || 972 primitiveType == "bytes29[]" || 973 primitiveType == "bytes30" || 974 primitiveType == "bytes30[]" || 975 primitiveType == "bytes31" || 976 primitiveType == "bytes31[]" || 977 primitiveType == "bytes32" || 978 primitiveType == "bytes32[]" { 979 return true 980 } 981 if primitiveType == "int" || 982 primitiveType == "int[]" || 983 primitiveType == "int8" || 984 primitiveType == "int8[]" || 985 primitiveType == "int16" || 986 primitiveType == "int16[]" || 987 primitiveType == "int32" || 988 primitiveType == "int32[]" || 989 primitiveType == "int64" || 990 primitiveType == "int64[]" || 991 primitiveType == "int128" || 992 primitiveType == "int128[]" || 993 primitiveType == "int256" || 994 primitiveType == "int256[]" { 995 return true 996 } 997 if primitiveType == "uint" || 998 primitiveType == "uint[]" || 999 primitiveType == "uint8" || 1000 primitiveType == "uint8[]" || 1001 primitiveType == "uint16" || 1002 primitiveType == "uint16[]" || 1003 primitiveType == "uint32" || 1004 primitiveType == "uint32[]" || 1005 primitiveType == "uint64" || 1006 primitiveType == "uint64[]" || 1007 primitiveType == "uint128" || 1008 primitiveType == "uint128[]" || 1009 primitiveType == "uint256" || 1010 primitiveType == "uint256[]" { 1011 return true 1012 } 1013 return false 1014 } 1015 1016 // validate checks if the given domain is valid, i.e. contains at least 1017 // the minimum viable keys and values 1018 func (domain *TypedDataDomain) validate() error { 1019 if domain.ChainId == nil && len(domain.Name) == 0 && len(domain.Version) == 0 && len(domain.VerifyingContract) == 0 && len(domain.Salt) == 0 { 1020 return errors.New("domain is undefined") 1021 } 1022 1023 return nil 1024 } 1025 1026 // Map is a helper function to generate a map version of the domain 1027 func (domain *TypedDataDomain) Map() map[string]interface{} { 1028 dataMap := map[string]interface{}{} 1029 1030 if domain.ChainId != nil { 1031 dataMap["chainId"] = domain.ChainId 1032 } 1033 1034 if len(domain.Name) > 0 { 1035 dataMap["name"] = domain.Name 1036 } 1037 1038 if len(domain.Version) > 0 { 1039 dataMap["version"] = domain.Version 1040 } 1041 1042 if len(domain.VerifyingContract) > 0 { 1043 dataMap["verifyingContract"] = domain.VerifyingContract 1044 } 1045 1046 if len(domain.Salt) > 0 { 1047 dataMap["salt"] = domain.Salt 1048 } 1049 return dataMap 1050 }