github.com/status-im/status-go@v1.1.0/eth-node/bridge/geth/ens/ens.go (about) 1 package ens 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/elliptic" 7 "encoding/hex" 8 "math/big" 9 "time" 10 11 ens "github.com/wealdtech/go-ens/v3" 12 "go.uber.org/zap" 13 14 "github.com/ethereum/go-ethereum/common" 15 "github.com/ethereum/go-ethereum/ethclient" 16 17 "github.com/status-im/status-go/eth-node/crypto" 18 enstypes "github.com/status-im/status-go/eth-node/types/ens" 19 ) 20 21 const ( 22 contractQueryTimeout = 5000 * time.Millisecond 23 ) 24 25 type Verifier struct { 26 logger *zap.Logger 27 } 28 29 // NewVerifier returns a Verifier attached to the specified logger 30 func NewVerifier(logger *zap.Logger) *Verifier { 31 return &Verifier{logger: logger} 32 } 33 34 func (m *Verifier) ReverseResolve(address common.Address, rpcEndpoint string) (string, error) { 35 ctx, cancel := context.WithTimeout(context.Background(), contractQueryTimeout) 36 defer cancel() 37 38 ethClient, err := ethclient.DialContext(ctx, rpcEndpoint) 39 if err != nil { 40 return "", err 41 } 42 return ens.ReverseResolve(ethClient, address) 43 } 44 45 func (m *Verifier) verifyENSName(ensInfo enstypes.ENSDetails, ethclient *ethclient.Client) enstypes.ENSResponse { 46 publicKeyStr := ensInfo.PublicKeyString 47 ensName := ensInfo.Name 48 m.logger.Info("Resolving ENS name", zap.String("name", ensName), zap.String("publicKey", publicKeyStr)) 49 response := enstypes.ENSResponse{ 50 Name: ensName, 51 PublicKeyString: publicKeyStr, 52 VerifiedAt: time.Now().Unix(), 53 } 54 55 expectedPubKeyBytes, err := hex.DecodeString(publicKeyStr) 56 if err != nil { 57 response.Error = err 58 return response 59 } 60 61 publicKey, err := crypto.UnmarshalPubkey(expectedPubKeyBytes) 62 if err != nil { 63 response.Error = err 64 return response 65 } 66 67 // Resolve ensName 68 resolver, err := ens.NewResolver(ethclient, ensName) 69 if err != nil { 70 m.logger.Error("error while creating ENS name resolver", zap.String("ensName", ensName), zap.Error(err)) 71 response.Error = err 72 return response 73 } 74 x, y, err := resolver.PubKey() 75 if err != nil { 76 m.logger.Error("error while resolving public key from ENS name", zap.String("ensName", ensName), zap.Error(err)) 77 response.Error = err 78 return response 79 } 80 81 // Assemble the bytes returned for the pubkey 82 pubKeyBytes := elliptic.Marshal(crypto.S256(), new(big.Int).SetBytes(x[:]), new(big.Int).SetBytes(y[:])) 83 84 response.PublicKey = publicKey 85 response.Verified = bytes.Equal(pubKeyBytes, expectedPubKeyBytes) 86 return response 87 } 88 89 // CheckBatch verifies that a registered ENS name matches the expected public key 90 func (m *Verifier) CheckBatch(ensDetails []enstypes.ENSDetails, rpcEndpoint, contractAddress string) (map[string]enstypes.ENSResponse, error) { 91 ctx, cancel := context.WithTimeout(context.Background(), contractQueryTimeout) 92 defer cancel() 93 94 ch := make(chan enstypes.ENSResponse) 95 response := make(map[string]enstypes.ENSResponse) 96 97 ethclient, err := ethclient.DialContext(ctx, rpcEndpoint) 98 if err != nil { 99 return nil, err 100 } 101 102 for _, ensInfo := range ensDetails { 103 go func(info enstypes.ENSDetails) { ch <- m.verifyENSName(info, ethclient) }(ensInfo) 104 } 105 106 for range ensDetails { 107 r := <-ch 108 response[r.PublicKeyString] = r 109 } 110 close(ch) 111 112 return response, nil 113 }