2019-11-04 10:08:22 +00:00
|
|
|
package ens
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"crypto/elliptic"
|
|
|
|
"encoding/hex"
|
2019-11-23 17:57:05 +00:00
|
|
|
"math/big"
|
|
|
|
"time"
|
|
|
|
|
2020-01-02 09:10:19 +00:00
|
|
|
ens "github.com/wealdtech/go-ens/v3"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2023-05-04 15:40:52 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2019-11-04 10:08:22 +00:00
|
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
2020-01-02 09:10:19 +00:00
|
|
|
|
2024-09-26 22:37:32 +00:00
|
|
|
gocommon "github.com/status-im/status-go/common"
|
2019-11-23 17:57:05 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
|
|
|
enstypes "github.com/status-im/status-go/eth-node/types/ens"
|
2019-11-04 10:08:22 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
contractQueryTimeout = 5000 * time.Millisecond
|
|
|
|
)
|
|
|
|
|
2020-02-10 11:22:37 +00:00
|
|
|
type Verifier struct {
|
2019-11-04 10:08:22 +00:00
|
|
|
logger *zap.Logger
|
|
|
|
}
|
|
|
|
|
2020-02-10 11:22:37 +00:00
|
|
|
// NewVerifier returns a Verifier attached to the specified logger
|
|
|
|
func NewVerifier(logger *zap.Logger) *Verifier {
|
|
|
|
return &Verifier{logger: logger}
|
2019-11-04 10:08:22 +00:00
|
|
|
}
|
|
|
|
|
2023-05-04 15:40:52 +00:00
|
|
|
func (m *Verifier) ReverseResolve(address common.Address, rpcEndpoint string) (string, error) {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), contractQueryTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
ethClient, err := ethclient.DialContext(ctx, rpcEndpoint)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return ens.ReverseResolve(ethClient, address)
|
|
|
|
}
|
|
|
|
|
2020-02-10 11:22:37 +00:00
|
|
|
func (m *Verifier) verifyENSName(ensInfo enstypes.ENSDetails, ethclient *ethclient.Client) enstypes.ENSResponse {
|
2019-11-04 10:08:22 +00:00
|
|
|
publicKeyStr := ensInfo.PublicKeyString
|
|
|
|
ensName := ensInfo.Name
|
|
|
|
m.logger.Info("Resolving ENS name", zap.String("name", ensName), zap.String("publicKey", publicKeyStr))
|
2019-11-23 17:57:05 +00:00
|
|
|
response := enstypes.ENSResponse{
|
2019-11-04 10:08:22 +00:00
|
|
|
Name: ensName,
|
|
|
|
PublicKeyString: publicKeyStr,
|
|
|
|
VerifiedAt: time.Now().Unix(),
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedPubKeyBytes, err := hex.DecodeString(publicKeyStr)
|
|
|
|
if err != nil {
|
|
|
|
response.Error = err
|
|
|
|
return response
|
|
|
|
}
|
|
|
|
|
|
|
|
publicKey, err := crypto.UnmarshalPubkey(expectedPubKeyBytes)
|
|
|
|
if err != nil {
|
|
|
|
response.Error = err
|
|
|
|
return response
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve ensName
|
|
|
|
resolver, err := ens.NewResolver(ethclient, ensName)
|
|
|
|
if err != nil {
|
|
|
|
m.logger.Error("error while creating ENS name resolver", zap.String("ensName", ensName), zap.Error(err))
|
|
|
|
response.Error = err
|
|
|
|
return response
|
|
|
|
}
|
|
|
|
x, y, err := resolver.PubKey()
|
|
|
|
if err != nil {
|
|
|
|
m.logger.Error("error while resolving public key from ENS name", zap.String("ensName", ensName), zap.Error(err))
|
|
|
|
response.Error = err
|
|
|
|
return response
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assemble the bytes returned for the pubkey
|
|
|
|
pubKeyBytes := elliptic.Marshal(crypto.S256(), new(big.Int).SetBytes(x[:]), new(big.Int).SetBytes(y[:]))
|
|
|
|
|
|
|
|
response.PublicKey = publicKey
|
|
|
|
response.Verified = bytes.Equal(pubKeyBytes, expectedPubKeyBytes)
|
|
|
|
return response
|
|
|
|
}
|
|
|
|
|
|
|
|
// CheckBatch verifies that a registered ENS name matches the expected public key
|
2020-02-10 11:22:37 +00:00
|
|
|
func (m *Verifier) CheckBatch(ensDetails []enstypes.ENSDetails, rpcEndpoint, contractAddress string) (map[string]enstypes.ENSResponse, error) {
|
2019-11-04 10:08:22 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), contractQueryTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2019-11-23 17:57:05 +00:00
|
|
|
ch := make(chan enstypes.ENSResponse)
|
|
|
|
response := make(map[string]enstypes.ENSResponse)
|
2019-11-04 10:08:22 +00:00
|
|
|
|
|
|
|
ethclient, err := ethclient.DialContext(ctx, rpcEndpoint)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, ensInfo := range ensDetails {
|
2024-09-26 22:37:32 +00:00
|
|
|
go func(info enstypes.ENSDetails) {
|
|
|
|
defer gocommon.LogOnPanic()
|
|
|
|
ch <- m.verifyENSName(info, ethclient)
|
|
|
|
}(ensInfo)
|
2019-11-04 10:08:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for range ensDetails {
|
|
|
|
r := <-ch
|
|
|
|
response[r.PublicKeyString] = r
|
|
|
|
}
|
|
|
|
close(ch)
|
|
|
|
|
|
|
|
return response, nil
|
|
|
|
}
|