From d57b2566234788cb420ae7c2c7f452ae339f8a03 Mon Sep 17 00:00:00 2001 From: daveroga Date: Tue, 16 Jul 2024 12:09:59 +0200 Subject: [PATCH 01/18] add signature in identity state result and tests --- cmd/driver/main.go | 2 +- go.mod | 6 +- go.sum | 14 ++ pkg/app/configs/driver.go | 1 + pkg/services/blockchain/eth/resolver.go | 207 ++++++++++++++++++- pkg/services/blockchain/eth/resolver_test.go | 116 ++++++++++- pkg/services/did.go | 1 + pkg/services/registry.go | 1 + 8 files changed, 340 insertions(+), 8 deletions(-) diff --git a/cmd/driver/main.go b/cmd/driver/main.go index 7042f31..733a8ba 100644 --- a/cmd/driver/main.go +++ b/cmd/driver/main.go @@ -63,7 +63,7 @@ func initResolvers() *services.ResolverRegistry { for chainName, chainSettings := range rs { for networkName, networkSettings := range chainSettings { prefix := fmt.Sprintf("%s:%s", chainName, networkName) - resolver, err := eth.NewResolver(networkSettings.NetworkURL, networkSettings.ContractAddress) + resolver, err := eth.NewResolver(networkSettings.NetworkURL, networkSettings.ContractAddress, networkSettings.WalletKey) if err != nil { log.Fatalf("failed configure resolver for network '%s': %v", prefix, err) } diff --git a/go.mod b/go.mod index 84ec413..884fb34 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/golang/mock v1.6.0 github.com/iden3/contracts-abi/state/go/abi v0.0.0-20230405152923-4a25f6f1f0f4 github.com/iden3/go-iden3-core/v2 v2.2.0 - github.com/iden3/go-schema-processor/v2 v2.4.2 + github.com/iden3/go-schema-processor/v2 v2.4.3-0.20240716072750-b7d560a31765 github.com/kelseyhightower/envconfig v1.4.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 @@ -18,6 +18,8 @@ require ( ) require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect github.com/dchest/blake512 v1.0.0 // indirect github.com/deckarep/golang-set/v2 v2.2.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -55,6 +57,8 @@ require ( github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 + github.com/tyler-smith/go-bip39 v1.1.0 github.com/wealdtech/go-multicodec v1.4.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect golang.org/x/sys v0.15.0 // indirect diff --git a/go.sum b/go.sum index cddfa4b..3411bfa 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,8 @@ github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -20,6 +24,7 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= @@ -79,6 +84,8 @@ github.com/iden3/go-merkletree-sql/v2 v2.0.4 h1:Dp089P3YNX1BE8+T1tKQHWTtnk84Y/Kr github.com/iden3/go-merkletree-sql/v2 v2.0.4/go.mod h1:kRhHKYpui5DUsry5RpveP6IC4XMe6iApdV9VChRYuEk= github.com/iden3/go-schema-processor/v2 v2.4.2 h1:t9pMxSpyMDAU3xSpn2dTvnTUUAtPlwOcNavbgXEFiJk= github.com/iden3/go-schema-processor/v2 v2.4.2/go.mod h1:eBtILnPjh4wnsAg3LWnvcZlGG+5IkAJaRqhVBnDjerg= +github.com/iden3/go-schema-processor/v2 v2.4.3-0.20240716072750-b7d560a31765 h1:UDdW0gP8GoOFVcIGrsAgDGAcLzI2IXSFMDQ2KYxd38k= +github.com/iden3/go-schema-processor/v2 v2.4.3-0.20240716072750-b7d560a31765/go.mod h1:eBtILnPjh4wnsAg3LWnvcZlGG+5IkAJaRqhVBnDjerg= github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -147,6 +154,7 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -155,7 +163,10 @@ github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+Kd github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/wealdtech/go-ens/v3 v3.5.5 h1:/jq3CDItK0AsFnZtiFJK44JthkAMD5YE3WAJOh4i7lc= github.com/wealdtech/go-ens/v3 v3.5.5/go.mod h1:w0EDKIm0dIQnqEKls6ORat/or+AVfPEdEXVfN71EeEE= @@ -166,11 +177,13 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRT github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= @@ -220,5 +233,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= diff --git a/pkg/app/configs/driver.go b/pkg/app/configs/driver.go index 42c1479..e3be040 100644 --- a/pkg/app/configs/driver.go +++ b/pkg/app/configs/driver.go @@ -16,6 +16,7 @@ const defaultPathToResolverSettings = "./resolvers.settings.yaml" type ResolverSettings map[string]map[string]struct { ContractAddress string `yaml:"contractAddress"` NetworkURL string `yaml:"networkURL"` + WalletKey string `yaml:"walletKey"` } // Config structure represent yaml config for did driver. diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index a42bcf2..47d61dc 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -2,13 +2,21 @@ package eth import ( "context" + "crypto/ecdsa" + "crypto/subtle" + "encoding/hex" "errors" "fmt" + "log" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/iden3/contracts-abi/state/go/abi" "github.com/iden3/driver-did-polygonid/pkg/services" core "github.com/iden3/go-iden3-core/v2" @@ -26,10 +34,16 @@ type StateContract interface { } type Resolver struct { - state StateContract - + state StateContract contractAddress string chainID int + walletKey string +} + +type AuthData struct { + TypedData apitypes.TypedData + Signature string + Address string } var ( @@ -38,8 +52,25 @@ var ( stateNotFoundException = "execution reverted: State does not exist" ) +var apiTypes = apitypes.Types{ + "IdentityState": []apitypes.Type{ + {Name: "from", Type: "address"}, + {Name: "state", Type: "uint256"}, + {Name: "gistRoot", Type: "uint256"}, + {Name: "identity", Type: "uint256"}, + }, + "EIP712Domain": []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "version", Type: "string"}, + {Name: "salt", Type: "string"}, + }, +} + +var primaryType = "IdentityState" + // NewResolver create new ethereum resolver. -func NewResolver(url, address string) (*Resolver, error) { +func NewResolver(url, address, walletKey string) (*Resolver, error) { c, err := ethclient.Dial(url) if err != nil { return nil, err @@ -52,6 +83,7 @@ func NewResolver(url, address string) (*Resolver, error) { resolver := &Resolver{ state: sc, contractAddress: address, + walletKey: walletKey, } chainID, err := c.NetworkID(context.Background()) if err != nil { @@ -125,8 +157,12 @@ func (r *Resolver) Resolve( stateInfo, gistInfo, err = r.resolveLatest(ctx, userID) } + stateInfoState := "" + gistInfoRoot := "" + identityState := services.IdentityState{} if stateInfo != nil { + stateInfoState = stateInfo.State.String() identityState.StateInfo = &services.StateInfo{ ID: did, State: stateInfo.State, @@ -138,6 +174,7 @@ func (r *Resolver) Resolve( } } if gistInfo != nil { + gistInfoRoot = gistInfo.Root.String() identityState.GistInfo = &services.GistInfo{ Root: gistInfo.Root, ReplacedByRoot: gistInfo.ReplacedByRoot, @@ -148,9 +185,173 @@ func (r *Resolver) Resolve( } } + signature := "" + if r.walletKey != "" { + signature, err = r.signTypedData(userID.BigInt().String(), stateInfoState, gistInfoRoot) + if err != nil { + return services.IdentityState{}, err + } + } + + identityState.Signature = signature + + // verified, _ := r.VerifyIdentityState(identityState, did) + // log.Println("VERIFIED:", verified) + return identityState, err } +func (r *Resolver) VerifyIdentityState( + identityState services.IdentityState, + did w3c.DID, +) (bool, error) { + userID, err := core.IDFromDID(did) + if err != nil { + return false, + fmt.Errorf("invalid did format for did '%s': %v", identityState.StateInfo.ID, err) + } + privateKey, err := crypto.HexToECDSA(r.walletKey) + if err != nil { + return false, err + } + + publicKey := privateKey.Public() + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + return false, errors.New("error casting public key to ECDSA") + } + + walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) + stateInfoState := "" + gistInfoRoot := "" + if identityState.StateInfo != nil { + stateInfoState = identityState.StateInfo.State.String() + } + if identityState.GistInfo != nil { + gistInfoRoot = identityState.GistInfo.Root.String() + } + + typedData := r.getTypedData(userID.BigInt().String(), stateInfoState, gistInfoRoot, walletAddress.String()) + + authData := AuthData{TypedData: typedData, Signature: identityState.Signature, Address: walletAddress.String()} + return r.verifyTypedData(authData) +} + +func (r *Resolver) getTypedData(identity string, state string, gistRoot string, walletAddress string) apitypes.TypedData { + salt := "resolver-123" + + typedData := apitypes.TypedData{ + Types: apiTypes, + PrimaryType: primaryType, + Domain: apitypes.TypedDataDomain{ + Name: "StateInfo", + Version: "1", + Salt: salt, + ChainId: math.NewHexOrDecimal256(int64(r.chainID)), + }, + Message: apitypes.TypedDataMessage{ + "from": walletAddress, + "state": state, + "gistRoot": gistRoot, + "identity": identity, + }, + } + + return typedData +} + +func (r *Resolver) signTypedData(identity string, state string, gistRoot string) (string, error) { + privateKey, err := crypto.HexToECDSA(r.walletKey) + if err != nil { + return "", err + } + + publicKey := privateKey.Public() + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + return "", errors.New("error casting public key to ECDSA") + } + + walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) + + typedData := r.getTypedData(identity, state, gistRoot, walletAddress.String()) + + domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) + if err != nil { + return "", err + } + typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) + if err != nil { + return "", err + } + rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) + dataHash := crypto.Keccak256(rawData) + + signature, err := crypto.Sign(dataHash, privateKey) + if err != nil { + return "", err + } + + if signature[64] < 27 { + signature[64] += 27 + } + + return "0x" + hex.EncodeToString(signature), nil +} + +func (r *Resolver) verifyTypedData(authData AuthData) (bool, error) { + signature, err := hexutil.Decode(authData.Signature) + if err != nil { + log.Println("Error %w", err) + return false, fmt.Errorf("decode signature: %w", err) + } + + // EIP-712 typed data marshalling + domainSeparator, err := authData.TypedData.HashStruct("EIP712Domain", authData.TypedData.Domain.Map()) + if err != nil { + return false, fmt.Errorf("eip712domain hash struct: %w", err) + } + typedDataHash, err := authData.TypedData.HashStruct(authData.TypedData.PrimaryType, authData.TypedData.Message) + if err != nil { + return false, fmt.Errorf("primary type hash struct: %w", err) + } + + // add magic string prefix + rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) + sighash := crypto.Keccak256(rawData) + + // update the recovery id + // https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L442 + signature[64] -= 27 + + // get the pubkey used to sign this signature + sigPubkey, err := crypto.Ecrecover(sighash, signature) + if err != nil { + return false, fmt.Errorf("ecrecover: %w", err) + } + + // get the address to confirm it's the same one in the auth token + pubkey, err := crypto.UnmarshalPubkey(sigPubkey) + if err != nil { + return false, fmt.Errorf("unmarshal pub key: %w", err) + } + address := crypto.PubkeyToAddress(*pubkey) + + // verify the signature (not sure if this is actually required after ecrecover) + signatureNoRecoverID := signature[:len(signature)-1] + verified := crypto.VerifySignature(sigPubkey, sighash, signatureNoRecoverID) + if !verified { + return false, errors.New("verification failed") + } + + dataAddress := common.HexToAddress(authData.Address) + if subtle.ConstantTimeCompare(address.Bytes(), dataAddress.Bytes()) == 0 { + return false, errors.New("address mismatch") + } + + return true, nil +} + func (r *Resolver) resolveLatest( ctx context.Context, id core.ID, diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index a0875a0..b74ed3a 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -6,6 +6,7 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/crypto" "github.com/golang/mock/gomock" "github.com/iden3/contracts-abi/state/go/abi" "github.com/iden3/driver-did-polygonid/pkg/services" @@ -14,9 +15,11 @@ import ( "github.com/iden3/go-iden3-core/v2/w3c" "github.com/pkg/errors" "github.com/stretchr/testify/require" + "github.com/tyler-smith/go-bip32" + "github.com/tyler-smith/go-bip39" ) -var userDID, _ = w3c.ParseDID("did:polygonid:polygon:mumbai:2qJEaVmT5jBrtgBQ4m7b7bRYzWmvMyDjBZGP24QwvD") +var userDID, _ = w3c.ParseDID("did:polygonid:polygon:amoy:2qY71pSkdCsRetTHbUA4YqG7Hx63Ej2PeiJMzAdJ2V") func TestResolveGist_Success(t *testing.T) { tests := []struct { @@ -157,9 +160,9 @@ func TestResolve_Success(t *testing.T) { tt.contractMock(stateContract) resolver := Resolver{state: stateContract} - gistInfo, err := resolver.Resolve(context.Background(), *tt.userDID, tt.opts) + identityState, err := resolver.Resolve(context.Background(), *tt.userDID, tt.opts) require.NoError(t, err) - require.Equal(t, tt.expectedIdentityState, gistInfo) + require.Equal(t, tt.expectedIdentityState, identityState) ctrl.Finish() }) @@ -201,3 +204,110 @@ func TestNotFoundErr(t *testing.T) { }) } } + +func TestResolveSignature_Success(t *testing.T) { + tests := []struct { + name string + opts *services.ResolverOpts + userDID *w3c.DID + contractMock func(c *cm.MockStateContract) + expectedIdentityState services.IdentityState + }{ + { + name: "resolve identity state by gist", + opts: &services.ResolverOpts{ + GistRoot: big.NewInt(1), + }, + userDID: userDID, + contractMock: func(c *cm.MockStateContract) { + proof := abi.IStateGistProof{ + Root: big.NewInt(4), + Existence: true, + Value: big.NewInt(5), + } + userID, _ := core.IDFromDID(*userDID) + c.EXPECT().GetGISTProofByRoot(gomock.Any(), userID.BigInt(), big.NewInt(1)).Return(proof, nil) + gistInfo := abi.IStateGistRootInfo{Root: big.NewInt(555)} + c.EXPECT().GetGISTRootInfo(gomock.Any(), big.NewInt(4)).Return(gistInfo, nil) + stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(444)} + c.EXPECT().GetStateInfoByIdAndState(gomock.Any(), gomock.Any(), big.NewInt(5)).Return(stateInfo, nil) + }, + expectedIdentityState: services.IdentityState{ + StateInfo: &services.StateInfo{ + ID: *userDID, + State: big.NewInt(444), + }, + GistInfo: &services.GistInfo{ + Root: big.NewInt(555), + }, + Signature: "0xae5dec0aaebed043dc78e9a2beef4dd355eaae7ed63958c725b4917e1246dffe0eae7f85438c1c500c891c59dff8b5ee55c1a52c09fcd42418a154ba32b00d431c", + }, + }, + { + name: "resolve identity state by state", + opts: &services.ResolverOpts{ + State: big.NewInt(1), + }, + userDID: userDID, + contractMock: func(c *cm.MockStateContract) { + userID, _ := core.IDFromDID(*userDID) + res := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555)} + c.EXPECT().GetStateInfoByIdAndState(gomock.Any(), gomock.Any(), big.NewInt(1)).Return(res, nil) + }, + expectedIdentityState: services.IdentityState{ + StateInfo: &services.StateInfo{ + ID: *userDID, + State: big.NewInt(555), + }, + GistInfo: nil, + Signature: "0xb84222149169ccbca64716c9bf932779feebadfdd1a2e3ecc8376af69352e9be4380a7aebe7c1442a94e2fc139ed4f193820454b9b4ad926e0da267b5e1968301c", + }, + }, + { + name: "resolve latest state", + opts: &services.ResolverOpts{}, + userDID: userDID, + contractMock: func(c *cm.MockStateContract) { + userID, _ := core.IDFromDID(*userDID) + latestGist := big.NewInt(100) + c.EXPECT().GetGISTRoot(gomock.Any()).Return(latestGist, nil) + latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400)} + c.EXPECT().GetGISTRootInfo(gomock.Any(), latestGist).Return(latestGistInfo, nil) + stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555)} + c.EXPECT().GetStateInfoById(gomock.Any(), userID.BigInt()).Return(stateInfo, nil) + }, + expectedIdentityState: services.IdentityState{ + StateInfo: &services.StateInfo{ + ID: *userDID, + State: big.NewInt(555), + }, + GistInfo: &services.GistInfo{ + Root: big.NewInt(400), + }, + Signature: "0x92df22c50364bbb1b18a03df7b651b2e5287eb05fc631f313195dca3d0255d5155407b15cb60622ba48d94fb134342dbcb1a34318a11e316de8a37a16dc9b7821b", + }, + }, + } + + mnemonic := "rib satisfy drastic trigger trial exclude raccoon wedding then gaze fire hero" + seed := bip39.NewSeed(mnemonic, "Secret Passphrase bla bla bla") + masterPrivateKey, _ := bip32.NewMasterKey(seed) + ecdaPrivateKey := crypto.ToECDSAUnsafe(masterPrivateKey.Key) + privateKeyHex := fmt.Sprintf("%x", ecdaPrivateKey.D) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + stateContract := cm.NewMockStateContract(ctrl) + tt.contractMock(stateContract) + resolver := Resolver{state: stateContract, chainID: 1, walletKey: privateKeyHex} + identityState, err := resolver.Resolve(context.Background(), *tt.userDID, tt.opts) + require.NoError(t, err) + require.Equal(t, tt.expectedIdentityState, identityState) + + ok, _ := resolver.VerifyIdentityState(identityState, *tt.userDID) + require.Equal(t, true, ok) + ctrl.Finish() + }) + } +} diff --git a/pkg/services/did.go b/pkg/services/did.go index 76d5484..40ae718 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -123,6 +123,7 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op Published: &isPublished, Info: info, Global: gist, + Signature: identityState.Signature, }, }, ) diff --git a/pkg/services/registry.go b/pkg/services/registry.go index 86dc1d0..c4c688d 100644 --- a/pkg/services/registry.go +++ b/pkg/services/registry.go @@ -21,6 +21,7 @@ var ( type IdentityState struct { StateInfo *StateInfo GistInfo *GistInfo + Signature string } type StateInfo struct { From 476275168130280a165b6700992e85d38610f84f Mon Sep 17 00:00:00 2001 From: daveroga Date: Tue, 16 Jul 2024 18:28:02 +0200 Subject: [PATCH 02/18] add proof in didResolutionMetadata --- go.mod | 2 +- go.sum | 2 - pkg/document/did.go | 9 +- pkg/document/proof.go | 61 ++++++++++++++ pkg/document/proof_test.go | 104 ++++++++++++++++++++++++ pkg/services/blockchain/eth/resolver.go | 50 +++++++++--- pkg/services/did.go | 32 +++++++- pkg/services/registry.go | 3 + 8 files changed, 242 insertions(+), 21 deletions(-) create mode 100644 pkg/document/proof.go create mode 100644 pkg/document/proof_test.go diff --git a/go.mod b/go.mod index 884fb34..0992c6f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/golang/mock v1.6.0 github.com/iden3/contracts-abi/state/go/abi v0.0.0-20230405152923-4a25f6f1f0f4 github.com/iden3/go-iden3-core/v2 v2.2.0 - github.com/iden3/go-schema-processor/v2 v2.4.3-0.20240716072750-b7d560a31765 + github.com/iden3/go-schema-processor/v2 v2.4.2 github.com/kelseyhightower/envconfig v1.4.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index 3411bfa..44d2ce2 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,6 @@ github.com/iden3/go-merkletree-sql/v2 v2.0.4 h1:Dp089P3YNX1BE8+T1tKQHWTtnk84Y/Kr github.com/iden3/go-merkletree-sql/v2 v2.0.4/go.mod h1:kRhHKYpui5DUsry5RpveP6IC4XMe6iApdV9VChRYuEk= github.com/iden3/go-schema-processor/v2 v2.4.2 h1:t9pMxSpyMDAU3xSpn2dTvnTUUAtPlwOcNavbgXEFiJk= github.com/iden3/go-schema-processor/v2 v2.4.2/go.mod h1:eBtILnPjh4wnsAg3LWnvcZlGG+5IkAJaRqhVBnDjerg= -github.com/iden3/go-schema-processor/v2 v2.4.3-0.20240716072750-b7d560a31765 h1:UDdW0gP8GoOFVcIGrsAgDGAcLzI2IXSFMDQ2KYxd38k= -github.com/iden3/go-schema-processor/v2 v2.4.3-0.20240716072750-b7d560a31765/go.mod h1:eBtILnPjh4wnsAg3LWnvcZlGG+5IkAJaRqhVBnDjerg= github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= diff --git a/pkg/document/did.go b/pkg/document/did.go index c096c6f..6338ff2 100644 --- a/pkg/document/did.go +++ b/pkg/document/did.go @@ -80,10 +80,11 @@ func NewDidErrorResolution(errCode ErrorCode, errMsg string) *DidResolution { // DidResolutionMetadata representation of resolution metadata. type DidResolutionMetadata struct { - Error ErrorCode `json:"error,omitempty"` - Message string `json:"message,omitempty"` - ContentType string `json:"contentType,omitempty"` - Retrieved time.Time `json:"retrieved,omitempty"` + Error ErrorCode `json:"error,omitempty"` + Message string `json:"message,omitempty"` + ContentType string `json:"contentType,omitempty"` + Retrieved time.Time `json:"retrieved,omitempty"` + Proof DidResolutionProofs `json:"proof,omitempty"` } // DidDocumentMetadata metadata of did document. diff --git a/pkg/document/proof.go b/pkg/document/proof.go new file mode 100644 index 0000000..c4511b1 --- /dev/null +++ b/pkg/document/proof.go @@ -0,0 +1,61 @@ +package document + +import ( + "encoding/json" + "errors" + "time" + + "github.com/ethereum/go-ethereum/signer/core/apitypes" + "github.com/iden3/go-schema-processor/v2/verifiable" +) + +type DidResolutionProof interface { + ProofType() verifiable.ProofType +} + +type DidResolutionProofs []DidResolutionProof + +type EthereumEip712SignatureProof2021 struct { + Type verifiable.ProofType `json:"type"` + ProofPursopose string `json:"proofPurpose"` + ProofValue string `json:"proofValue"` + VerificationMethod string `json:"verificationMethod"` + Created time.Time `json:"created"` + Eip712 apitypes.TypedData `json:"eip712"` +} + +// EthereumEip712Signature2021Type is a proof type for EIP172 signature proofs +const EthereumEip712SignatureProof2021Type verifiable.ProofType = "EthereumEip712Signature2021" + +func (p *EthereumEip712SignatureProof2021) ProofType() verifiable.ProofType { + return p.Type +} + +func (p *EthereumEip712SignatureProof2021) UnmarshalJSON(in []byte) error { + var obj struct { + Type verifiable.ProofType `json:"type"` + ProofPursopose string `json:"proofPurpose"` + ProofValue string `json:"proofValue"` + VerificationMethod string `json:"verificationMethod"` + Created time.Time `json:"created"` + Eip712 json.RawMessage `json:"eip712"` + } + err := json.Unmarshal(in, &obj) + if err != nil { + return err + } + if obj.Type != EthereumEip712SignatureProof2021Type { + return errors.New("invalid proof type") + } + p.Type = obj.Type + err = json.Unmarshal(obj.Eip712, &p.Eip712) + if err != nil { + return err + } + p.VerificationMethod = obj.VerificationMethod + p.ProofPursopose = obj.ProofPursopose + // TODO: validate proof value + p.ProofValue = obj.ProofValue + p.Created = obj.Created + return nil +} diff --git a/pkg/document/proof_test.go b/pkg/document/proof_test.go new file mode 100644 index 0000000..ee96669 --- /dev/null +++ b/pkg/document/proof_test.go @@ -0,0 +1,104 @@ +package document + +import ( + "encoding/json" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + "github.com/stretchr/testify/require" +) + +func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { + in := `{ + "type": "EthereumEip712Signature2021", + "proofPurpose": "assertionMethod", + "proofValue": "0xd5e5ffe290a258116a0f7acb4c9a5bbfdd842516061c6a794892b6db05fbd14706de7e189d965bead2ffb23e30d2f6b02ecf764e6fe24be788721049b7e331481c", + "verificationMethod": "did:pkh:eip155:1:0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7#blockchainAccountId", + "created": "2021-09-23T20:21:34Z", + "eip712": { + "types": { + "EIP712Domain": [ + { "name": "name", "type": "string" }, + { "name": "chainId", "type": "uint256" }, + { "name": "version", "type": "string" }, + { "name": "salt", "type": "string" } + ], + "IdentityState": [ + { "name": "from", "type": "address" }, + { "name": "state", "type": "uint256" }, + { "name": "gistRoot", "type": "uint256" }, + { "name": "identity", "type": "uint256" } + ] + }, + "primaryType": "IdentityState", + "domain": { + "name": "StateInfo", + "version": "1", + "chainId": "0x1", + "verifyingContract": "", + "salt": "resolver-123" + }, + "message": { + "from": "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7", + "gistRoot": "555", + "identity": "19090607534999372304474213543962416547920895595808567155882840509226423042", + "state": "444" + } + } + }` + var proof EthereumEip712SignatureProof2021 + err := json.Unmarshal([]byte(in), &proof) + require.NoError(t, err) + + timeParsed, _ := time.Parse("2006-01-02T15:04:05Z", "2021-09-23T20:21:34Z") + + var apiTypes = apitypes.Types{ + "IdentityState": []apitypes.Type{ + {Name: "from", Type: "address"}, + {Name: "state", Type: "uint256"}, + {Name: "gistRoot", Type: "uint256"}, + {Name: "identity", Type: "uint256"}, + }, + "EIP712Domain": []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "version", Type: "string"}, + {Name: "salt", Type: "string"}, + }, + } + + var primaryType = "IdentityState" + salt := "resolver-123" + walletAddress := "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7" + state := "444" + gistRoot := "555" + identity := "19090607534999372304474213543962416547920895595808567155882840509226423042" + chainID := 1 + + wantProof := EthereumEip712SignatureProof2021{ + Type: "EthereumEip712Signature2021", + ProofPursopose: "assertionMethod", + ProofValue: "0xd5e5ffe290a258116a0f7acb4c9a5bbfdd842516061c6a794892b6db05fbd14706de7e189d965bead2ffb23e30d2f6b02ecf764e6fe24be788721049b7e331481c", + VerificationMethod: "did:pkh:eip155:1:0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7#blockchainAccountId", + Created: timeParsed, + Eip712: apitypes.TypedData{ + Types: apiTypes, + PrimaryType: primaryType, + Domain: apitypes.TypedDataDomain{ + Name: "StateInfo", + Version: "1", + Salt: salt, + ChainId: math.NewHexOrDecimal256(int64(chainID)), + }, + Message: apitypes.TypedDataMessage{ + "from": walletAddress, + "state": state, + "gistRoot": gistRoot, + "identity": identity, + }, + }, + } + require.Equal(t, wantProof, proof) +} diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 47d61dc..077252a 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -7,7 +7,6 @@ import ( "encoding/hex" "errors" "fmt" - "log" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -97,6 +96,27 @@ func (r *Resolver) BlockchainID() string { return fmt.Sprintf("%d:%s", r.chainID, r.contractAddress) } +func (r *Resolver) WalletAddress() (string, error) { + if r.walletKey == "" { + return "", errors.New("wallet key is not set") + } + + privateKey, err := crypto.HexToECDSA(r.walletKey) + if err != nil { + return "", err + } + + publicKey := privateKey.Public() + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + return "", errors.New("error casting public key to ECDSA") + } + + walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) + + return walletAddress.String(), nil +} + func (r *Resolver) ResolveGist( ctx context.Context, opts *services.ResolverOpts, @@ -187,7 +207,7 @@ func (r *Resolver) Resolve( signature := "" if r.walletKey != "" { - signature, err = r.signTypedData(userID.BigInt().String(), stateInfoState, gistInfoRoot) + signature, err = r.signTypedData(did, stateInfoState, gistInfoRoot) if err != nil { return services.IdentityState{}, err } @@ -205,11 +225,6 @@ func (r *Resolver) VerifyIdentityState( identityState services.IdentityState, did w3c.DID, ) (bool, error) { - userID, err := core.IDFromDID(did) - if err != nil { - return false, - fmt.Errorf("invalid did format for did '%s': %v", identityState.StateInfo.ID, err) - } privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { return false, err @@ -231,13 +246,23 @@ func (r *Resolver) VerifyIdentityState( gistInfoRoot = identityState.GistInfo.Root.String() } - typedData := r.getTypedData(userID.BigInt().String(), stateInfoState, gistInfoRoot, walletAddress.String()) + typedData, err := r.TypedData(did, stateInfoState, gistInfoRoot, walletAddress.String()) + if err != nil { + return false, err + } authData := AuthData{TypedData: typedData, Signature: identityState.Signature, Address: walletAddress.String()} return r.verifyTypedData(authData) } -func (r *Resolver) getTypedData(identity string, state string, gistRoot string, walletAddress string) apitypes.TypedData { +func (r *Resolver) TypedData(did w3c.DID, state string, gistRoot string, walletAddress string) (apitypes.TypedData, error) { + userID, err := core.IDFromDID(did) + if err != nil { + return apitypes.TypedData{}, + fmt.Errorf("invalid did format for did '%s': %v", did, err) + } + identity := userID.BigInt().String() + salt := "resolver-123" typedData := apitypes.TypedData{ @@ -257,10 +282,10 @@ func (r *Resolver) getTypedData(identity string, state string, gistRoot string, }, } - return typedData + return typedData, nil } -func (r *Resolver) signTypedData(identity string, state string, gistRoot string) (string, error) { +func (r *Resolver) signTypedData(did w3c.DID, state string, gistRoot string) (string, error) { privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { return "", err @@ -274,7 +299,7 @@ func (r *Resolver) signTypedData(identity string, state string, gistRoot string) walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) - typedData := r.getTypedData(identity, state, gistRoot, walletAddress.String()) + typedData, err := r.TypedData(did, state, gistRoot, walletAddress.String()) domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) if err != nil { @@ -302,7 +327,6 @@ func (r *Resolver) signTypedData(identity string, state string, gistRoot string) func (r *Resolver) verifyTypedData(authData AuthData) (bool, error) { signature, err := hexutil.Decode(authData.Signature) if err != nil { - log.Println("Error %w", err) return false, fmt.Errorf("decode signature: %w", err) } diff --git a/pkg/services/did.go b/pkg/services/did.go index 40ae718..e2fa29a 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -6,6 +6,7 @@ import ( "math/big" "net" "strings" + "time" "github.com/iden3/driver-did-polygonid/pkg/document" "github.com/iden3/driver-did-polygonid/pkg/services/ens" @@ -123,11 +124,40 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op Published: &isPublished, Info: info, Global: gist, - Signature: identityState.Signature, }, }, ) + walletAddress, err := resolver.WalletAddress() + + if err == nil { + stateInfoState := "" + gistInfoRoot := "" + if identityState.StateInfo != nil { + stateInfoState = identityState.StateInfo.State.String() + } + + if identityState.GistInfo != nil { + gistInfoRoot = identityState.GistInfo.Root.String() + } + + eip712TypedData, err := resolver.TypedData(*userDID, stateInfoState, gistInfoRoot, walletAddress) + if err != nil { + return nil, fmt.Errorf("invalid typed data: %v", err) + } + + eip712Proof := &document.EthereumEip712SignatureProof2021{ + Type: document.EthereumEip712SignatureProof2021Type, + ProofPursopose: "assertionMethod", + ProofValue: identityState.Signature, + VerificationMethod: fmt.Sprintf("did:pkh:eip155:%s:%s#blockchainAccountId", strings.Split(chainIDStateAddress, ":")[0], walletAddress), + Eip712: eip712TypedData, + Created: time.Now(), + } + + didResolution.DidResolutionMetadata.Proof = append(didResolution.DidResolutionMetadata.Proof, eip712Proof) + } + return didResolution, nil } diff --git a/pkg/services/registry.go b/pkg/services/registry.go index c4c688d..72be8ac 100644 --- a/pkg/services/registry.go +++ b/pkg/services/registry.go @@ -5,6 +5,7 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/iden3/go-iden3-core/v2/w3c" "github.com/iden3/go-merkletree-sql/v2" "github.com/iden3/go-schema-processor/v2/verifiable" @@ -96,6 +97,8 @@ type Resolver interface { Resolve(ctx context.Context, did w3c.DID, opts *ResolverOpts) (IdentityState, error) ResolveGist(ctx context.Context, opts *ResolverOpts) (*GistInfo, error) BlockchainID() string + WalletAddress() (string, error) + TypedData(did w3c.DID, state string, gistRoot string, walletAddress string) (apitypes.TypedData, error) } type ResolverRegistry map[string]Resolver From 562896fffe5523165c5928ad73bf0be619a5e8e2 Mon Sep 17 00:00:00 2001 From: daveroga Date: Wed, 17 Jul 2024 12:05:20 +0200 Subject: [PATCH 03/18] update verifyingcontract domain --- pkg/document/proof_test.go | 19 +++++++++++-------- pkg/services/blockchain/eth/resolver.go | 12 +++++++----- pkg/services/blockchain/eth/resolver_test.go | 6 +++--- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/pkg/document/proof_test.go b/pkg/document/proof_test.go index ee96669..763c056 100644 --- a/pkg/document/proof_test.go +++ b/pkg/document/proof_test.go @@ -23,7 +23,8 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { { "name": "name", "type": "string" }, { "name": "chainId", "type": "uint256" }, { "name": "version", "type": "string" }, - { "name": "salt", "type": "string" } + { "name": "salt", "type": "string" }, + { "name": "verifyingContract", "type": "address" } ], "IdentityState": [ { "name": "from", "type": "address" }, @@ -37,8 +38,8 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { "name": "StateInfo", "version": "1", "chainId": "0x1", - "verifyingContract": "", - "salt": "resolver-123" + "verifyingContract": "0x0000000000000000000000000000000000000000", + "salt": "resolver-privado.id" }, "message": { "from": "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7", @@ -66,11 +67,12 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { {Name: "chainId", Type: "uint256"}, {Name: "version", Type: "string"}, {Name: "salt", Type: "string"}, + {Name: "verifyingContract", Type: "address"}, }, } var primaryType = "IdentityState" - salt := "resolver-123" + salt := "resolver-privado.id" walletAddress := "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7" state := "444" gistRoot := "555" @@ -87,10 +89,11 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { Types: apiTypes, PrimaryType: primaryType, Domain: apitypes.TypedDataDomain{ - Name: "StateInfo", - Version: "1", - Salt: salt, - ChainId: math.NewHexOrDecimal256(int64(chainID)), + Name: "StateInfo", + Version: "1", + Salt: salt, + ChainId: math.NewHexOrDecimal256(int64(chainID)), + VerifyingContract: "0x0000000000000000000000000000000000000000", }, Message: apitypes.TypedDataMessage{ "from": walletAddress, diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 077252a..9ccacd4 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -63,6 +63,7 @@ var apiTypes = apitypes.Types{ {Name: "chainId", Type: "uint256"}, {Name: "version", Type: "string"}, {Name: "salt", Type: "string"}, + {Name: "verifyingContract", Type: "address"}, }, } @@ -263,16 +264,17 @@ func (r *Resolver) TypedData(did w3c.DID, state string, gistRoot string, walletA } identity := userID.BigInt().String() - salt := "resolver-123" + salt := "resolver-privado.id" typedData := apitypes.TypedData{ Types: apiTypes, PrimaryType: primaryType, Domain: apitypes.TypedDataDomain{ - Name: "StateInfo", - Version: "1", - Salt: salt, - ChainId: math.NewHexOrDecimal256(int64(r.chainID)), + Name: "StateInfo", + Version: "1", + Salt: salt, + ChainId: math.NewHexOrDecimal256(int64(r.chainID)), + VerifyingContract: "0x0000000000000000000000000000000000000000", }, Message: apitypes.TypedDataMessage{ "from": walletAddress, diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index b74ed3a..0a4bcc0 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -240,7 +240,7 @@ func TestResolveSignature_Success(t *testing.T) { GistInfo: &services.GistInfo{ Root: big.NewInt(555), }, - Signature: "0xae5dec0aaebed043dc78e9a2beef4dd355eaae7ed63958c725b4917e1246dffe0eae7f85438c1c500c891c59dff8b5ee55c1a52c09fcd42418a154ba32b00d431c", + Signature: "0xd0488105cd2af066b7aa7cb36091cd6a9328b8c365df0914e7392a721918c76d42b644ae364258072a5436706bdbd65d603fd657814d17dcabba3c7bd31c7a411b", }, }, { @@ -260,7 +260,7 @@ func TestResolveSignature_Success(t *testing.T) { State: big.NewInt(555), }, GistInfo: nil, - Signature: "0xb84222149169ccbca64716c9bf932779feebadfdd1a2e3ecc8376af69352e9be4380a7aebe7c1442a94e2fc139ed4f193820454b9b4ad926e0da267b5e1968301c", + Signature: "0x0ee7c23eb141aa0d7e4a47469de211ec6d3ae01cb0850786112db15d5d7673164c2c9a3e1f3dc880cea4bf280e3bbeb52f4750f4d32152c20dcdefadc25212411c", }, }, { @@ -284,7 +284,7 @@ func TestResolveSignature_Success(t *testing.T) { GistInfo: &services.GistInfo{ Root: big.NewInt(400), }, - Signature: "0x92df22c50364bbb1b18a03df7b651b2e5287eb05fc631f313195dca3d0255d5155407b15cb60622ba48d94fb134342dbcb1a34318a11e316de8a37a16dc9b7821b", + Signature: "0xdb4a1e6e5cb5dce2c9815cb612edc19e7bcd655f5e1c72370753c4d2df9ea11a698a970f99915847e1e0146ef7f36adb97088d9f7143f7293af72c05fd3e4d991b", }, }, } From 7981761b06c464e41f5294188074250e00343d34 Mon Sep 17 00:00:00 2001 From: daveroga Date: Wed, 17 Jul 2024 12:14:44 +0200 Subject: [PATCH 04/18] fix order typeddata --- pkg/document/proof_test.go | 10 +++++----- pkg/services/blockchain/eth/resolver.go | 4 ++-- pkg/services/blockchain/eth/resolver_test.go | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/document/proof_test.go b/pkg/document/proof_test.go index 763c056..5978fc5 100644 --- a/pkg/document/proof_test.go +++ b/pkg/document/proof_test.go @@ -21,10 +21,10 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { "types": { "EIP712Domain": [ { "name": "name", "type": "string" }, - { "name": "chainId", "type": "uint256" }, { "name": "version", "type": "string" }, - { "name": "salt", "type": "string" }, - { "name": "verifyingContract", "type": "address" } + { "name": "chainId", "type": "uint256" }, + { "name": "verifyingContract", "type": "address" }, + { "name": "salt", "type": "string" } ], "IdentityState": [ { "name": "from", "type": "address" }, @@ -64,10 +64,10 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { }, "EIP712Domain": []apitypes.Type{ {Name: "name", Type: "string"}, - {Name: "chainId", Type: "uint256"}, {Name: "version", Type: "string"}, - {Name: "salt", Type: "string"}, + {Name: "chainId", Type: "uint256"}, {Name: "verifyingContract", Type: "address"}, + {Name: "salt", Type: "string"}, }, } diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 9ccacd4..4734a24 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -60,10 +60,10 @@ var apiTypes = apitypes.Types{ }, "EIP712Domain": []apitypes.Type{ {Name: "name", Type: "string"}, - {Name: "chainId", Type: "uint256"}, {Name: "version", Type: "string"}, - {Name: "salt", Type: "string"}, + {Name: "chainId", Type: "uint256"}, {Name: "verifyingContract", Type: "address"}, + {Name: "salt", Type: "string"}, }, } diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index 0a4bcc0..2d24e0f 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -240,7 +240,7 @@ func TestResolveSignature_Success(t *testing.T) { GistInfo: &services.GistInfo{ Root: big.NewInt(555), }, - Signature: "0xd0488105cd2af066b7aa7cb36091cd6a9328b8c365df0914e7392a721918c76d42b644ae364258072a5436706bdbd65d603fd657814d17dcabba3c7bd31c7a411b", + Signature: "0xfd0b364ceb42b65824daa75c5f0c1932a9e3430e871e3810b8155244d7ac67772b02b8c24356180d5112035e84536bdf2de4ea7d0116967b3331fc95b50a2a961b", }, }, { @@ -260,7 +260,7 @@ func TestResolveSignature_Success(t *testing.T) { State: big.NewInt(555), }, GistInfo: nil, - Signature: "0x0ee7c23eb141aa0d7e4a47469de211ec6d3ae01cb0850786112db15d5d7673164c2c9a3e1f3dc880cea4bf280e3bbeb52f4750f4d32152c20dcdefadc25212411c", + Signature: "0x0ec2b122b0f53aed76a006f9d9dde7e0ce0b67371d70983379e8f0ee99c8fae74fdc58687259221f7f7ac5ad4bf1654be189084507cd7f309565af1dc82322861c", }, }, { @@ -284,7 +284,7 @@ func TestResolveSignature_Success(t *testing.T) { GistInfo: &services.GistInfo{ Root: big.NewInt(400), }, - Signature: "0xdb4a1e6e5cb5dce2c9815cb612edc19e7bcd655f5e1c72370753c4d2df9ea11a698a970f99915847e1e0146ef7f36adb97088d9f7143f7293af72c05fd3e4d991b", + Signature: "0x5e44cee08048ec667ba6480f1c969ae68a41d8704fd4a778fb8bc16868def4ef0622774d88e3ec898b5e2f51ac46b621da5ae060c205778f19895c6f038b90331c", }, }, } From 7d9fb1d50b77a781e7245281c22fdd14a3c9a432 Mon Sep 17 00:00:00 2001 From: daveroga Date: Thu, 18 Jul 2024 07:32:47 +0200 Subject: [PATCH 05/18] add params for verifying contract --- pkg/app/handler.go | 20 ++++++++++- pkg/document/proof_test.go | 9 ++--- pkg/services/blockchain/eth/resolver.go | 35 ++++++++++++-------- pkg/services/blockchain/eth/resolver_test.go | 25 +++++++++----- pkg/services/did.go | 17 +++++++--- pkg/services/registry.go | 2 +- 6 files changed, 74 insertions(+), 34 deletions(-) diff --git a/pkg/app/handler.go b/pkg/app/handler.go index 03c886b..0d5d2ea 100644 --- a/pkg/app/handler.go +++ b/pkg/app/handler.go @@ -5,6 +5,8 @@ import ( "fmt" "log" "net/http" + "regexp" + "strconv" "strings" "github.com/iden3/driver-did-polygonid/pkg/services" @@ -23,6 +25,8 @@ func (d *DidDocumentHandler) Get(w http.ResponseWriter, r *http.Request) { opts, err := getResolverOpts( r.URL.Query().Get("state"), r.URL.Query().Get("gist"), + r.URL.Query().Get("verifyingContractChainId"), + r.URL.Query().Get("verifyingContractAddress"), ) if err != nil { log.Println("invalid options query:", err) @@ -110,7 +114,7 @@ func (d *DidDocumentHandler) GetGist(w http.ResponseWriter, r *http.Request) { } } -func getResolverOpts(state, gistRoot string) (ro services.ResolverOpts, err error) { +func getResolverOpts(state, gistRoot, verifyingContractChainId, verifyingContractAddress string) (ro services.ResolverOpts, err error) { if state != "" && gistRoot != "" { return ro, errors.New("'state' and 'gist root' cannot be used together") } @@ -128,5 +132,19 @@ func getResolverOpts(state, gistRoot string) (ro services.ResolverOpts, err erro } ro.GistRoot = g.BigInt() } + if verifyingContractChainId != "" { + i, err := strconv.Atoi(verifyingContractChainId) + if err != nil { + return ro, fmt.Errorf("invalid verifying contract chainId format: %v", err) + } + ro.VerifyingContractChainId = &i + } + if verifyingContractAddress != "" { + re := regexp.MustCompile("^0x[0-9a-fA-F]{40}$") + if !re.MatchString(verifyingContractAddress) { + return ro, fmt.Errorf("invalid verifying contract address format: %v", err) + } + ro.VerifyingContractAddress = verifyingContractAddress + } return } diff --git a/pkg/document/proof_test.go b/pkg/document/proof_test.go index 5978fc5..096506d 100644 --- a/pkg/document/proof_test.go +++ b/pkg/document/proof_test.go @@ -23,8 +23,7 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { { "name": "name", "type": "string" }, { "name": "version", "type": "string" }, { "name": "chainId", "type": "uint256" }, - { "name": "verifyingContract", "type": "address" }, - { "name": "salt", "type": "string" } + { "name": "verifyingContract", "type": "address" } ], "IdentityState": [ { "name": "from", "type": "address" }, @@ -38,8 +37,7 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { "name": "StateInfo", "version": "1", "chainId": "0x1", - "verifyingContract": "0x0000000000000000000000000000000000000000", - "salt": "resolver-privado.id" + "verifyingContract": "0x0000000000000000000000000000000000000000" }, "message": { "from": "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7", @@ -67,12 +65,10 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { {Name: "version", Type: "string"}, {Name: "chainId", Type: "uint256"}, {Name: "verifyingContract", Type: "address"}, - {Name: "salt", Type: "string"}, }, } var primaryType = "IdentityState" - salt := "resolver-privado.id" walletAddress := "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7" state := "444" gistRoot := "555" @@ -91,7 +87,6 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { Domain: apitypes.TypedDataDomain{ Name: "StateInfo", Version: "1", - Salt: salt, ChainId: math.NewHexOrDecimal256(int64(chainID)), VerifyingContract: "0x0000000000000000000000000000000000000000", }, diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 4734a24..16eef98 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -63,7 +63,6 @@ var apiTypes = apitypes.Types{ {Name: "version", Type: "string"}, {Name: "chainId", Type: "uint256"}, {Name: "verifyingContract", Type: "address"}, - {Name: "salt", Type: "string"}, }, } @@ -208,7 +207,15 @@ func (r *Resolver) Resolve( signature := "" if r.walletKey != "" { - signature, err = r.signTypedData(did, stateInfoState, gistInfoRoot) + verifyingContractChainId := 0 + if opts.VerifyingContractChainId == nil { + return services.IdentityState{}, errors.New("error verifying contract chainId is not set") + } + verifyingContractChainId = *opts.VerifyingContractChainId + if opts.VerifyingContractAddress == "" { + return services.IdentityState{}, errors.New("error verifying contract address is not set") + } + signature, err = r.signTypedData(verifyingContractChainId, opts.VerifyingContractAddress, did, stateInfoState, gistInfoRoot) if err != nil { return services.IdentityState{}, err } @@ -225,6 +232,8 @@ func (r *Resolver) Resolve( func (r *Resolver) VerifyIdentityState( identityState services.IdentityState, did w3c.DID, + verifyingContractChainId int, + verifyingContractAddress string, ) (bool, error) { privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { @@ -247,7 +256,7 @@ func (r *Resolver) VerifyIdentityState( gistInfoRoot = identityState.GistInfo.Root.String() } - typedData, err := r.TypedData(did, stateInfoState, gistInfoRoot, walletAddress.String()) + typedData, err := r.TypedData(verifyingContractChainId, verifyingContractAddress, did, stateInfoState, gistInfoRoot, walletAddress.String()) if err != nil { return false, err } @@ -256,7 +265,7 @@ func (r *Resolver) VerifyIdentityState( return r.verifyTypedData(authData) } -func (r *Resolver) TypedData(did w3c.DID, state string, gistRoot string, walletAddress string) (apitypes.TypedData, error) { +func (r *Resolver) TypedData(verifyingContractChainId int, verifyingContractAddress string, did w3c.DID, state string, gistRoot string, walletAddress string) (apitypes.TypedData, error) { userID, err := core.IDFromDID(did) if err != nil { return apitypes.TypedData{}, @@ -264,17 +273,14 @@ func (r *Resolver) TypedData(did w3c.DID, state string, gistRoot string, walletA } identity := userID.BigInt().String() - salt := "resolver-privado.id" - typedData := apitypes.TypedData{ Types: apiTypes, PrimaryType: primaryType, Domain: apitypes.TypedDataDomain{ Name: "StateInfo", Version: "1", - Salt: salt, - ChainId: math.NewHexOrDecimal256(int64(r.chainID)), - VerifyingContract: "0x0000000000000000000000000000000000000000", + ChainId: math.NewHexOrDecimal256(int64(verifyingContractChainId)), + VerifyingContract: verifyingContractAddress, }, Message: apitypes.TypedDataMessage{ "from": walletAddress, @@ -287,7 +293,7 @@ func (r *Resolver) TypedData(did w3c.DID, state string, gistRoot string, walletA return typedData, nil } -func (r *Resolver) signTypedData(did w3c.DID, state string, gistRoot string) (string, error) { +func (r *Resolver) signTypedData(verifyingContractChainId int, verifyingContractAddress string, did w3c.DID, state string, gistRoot string) (string, error) { privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { return "", err @@ -301,15 +307,18 @@ func (r *Resolver) signTypedData(did w3c.DID, state string, gistRoot string) (st walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) - typedData, err := r.TypedData(did, state, gistRoot, walletAddress.String()) + typedData, err := r.TypedData(verifyingContractChainId, verifyingContractAddress, did, state, gistRoot, walletAddress.String()) + if err != nil { + return "", errors.New("error getting typed data for signing") + } domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) if err != nil { - return "", err + return "", errors.New("error hashing EIP712Domain for signing") } typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) if err != nil { - return "", err + return "", errors.New("error hashing PrimaryType message for signing") } rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) dataHash := crypto.Keccak256(rawData) diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index 2d24e0f..9d81b41 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -206,6 +206,8 @@ func TestNotFoundErr(t *testing.T) { } func TestResolveSignature_Success(t *testing.T) { + verifyingContractChainId := new(int) + *verifyingContractChainId = 1 tests := []struct { name string opts *services.ResolverOpts @@ -216,7 +218,9 @@ func TestResolveSignature_Success(t *testing.T) { { name: "resolve identity state by gist", opts: &services.ResolverOpts{ - GistRoot: big.NewInt(1), + GistRoot: big.NewInt(1), + VerifyingContractChainId: verifyingContractChainId, + VerifyingContractAddress: "0x0000000000000000000000000000000000000000", }, userDID: userDID, contractMock: func(c *cm.MockStateContract) { @@ -240,13 +244,15 @@ func TestResolveSignature_Success(t *testing.T) { GistInfo: &services.GistInfo{ Root: big.NewInt(555), }, - Signature: "0xfd0b364ceb42b65824daa75c5f0c1932a9e3430e871e3810b8155244d7ac67772b02b8c24356180d5112035e84536bdf2de4ea7d0116967b3331fc95b50a2a961b", + Signature: "0x028ca69378ed198806eecebc722d1bfcf8fb5ca9232274f2403c2d6b4aa3199902555c672c474faec318de2d6974898d542f18f99f884000a22f29d0c2956d291c", }, }, { name: "resolve identity state by state", opts: &services.ResolverOpts{ - State: big.NewInt(1), + State: big.NewInt(1), + VerifyingContractChainId: verifyingContractChainId, + VerifyingContractAddress: "0x0000000000000000000000000000000000000000", }, userDID: userDID, contractMock: func(c *cm.MockStateContract) { @@ -260,12 +266,15 @@ func TestResolveSignature_Success(t *testing.T) { State: big.NewInt(555), }, GistInfo: nil, - Signature: "0x0ec2b122b0f53aed76a006f9d9dde7e0ce0b67371d70983379e8f0ee99c8fae74fdc58687259221f7f7ac5ad4bf1654be189084507cd7f309565af1dc82322861c", + Signature: "0xb23932bd8f5fc4674583b41ceade5aeb6113ea22b3f330e4deaaa432dfed9ab853dac55f531abd90a8c89b573444aeb974305c3a8aac3bc201531aad34383fbb1c", }, }, { - name: "resolve latest state", - opts: &services.ResolverOpts{}, + name: "resolve latest state", + opts: &services.ResolverOpts{ + VerifyingContractChainId: verifyingContractChainId, + VerifyingContractAddress: "0x0000000000000000000000000000000000000000", + }, userDID: userDID, contractMock: func(c *cm.MockStateContract) { userID, _ := core.IDFromDID(*userDID) @@ -284,7 +293,7 @@ func TestResolveSignature_Success(t *testing.T) { GistInfo: &services.GistInfo{ Root: big.NewInt(400), }, - Signature: "0x5e44cee08048ec667ba6480f1c969ae68a41d8704fd4a778fb8bc16868def4ef0622774d88e3ec898b5e2f51ac46b621da5ae060c205778f19895c6f038b90331c", + Signature: "0x5a9ea69f9311ac800a3fc2375cf6fa4d4646b5b2b55219f934755177c93d367a152e4ab7585600598f280485c41471a782dc6ef3e1fd235bd48e4441446ec24d1b", }, }, } @@ -305,7 +314,7 @@ func TestResolveSignature_Success(t *testing.T) { require.NoError(t, err) require.Equal(t, tt.expectedIdentityState, identityState) - ok, _ := resolver.VerifyIdentityState(identityState, *tt.userDID) + ok, _ := resolver.VerifyIdentityState(identityState, *tt.userDID, *tt.opts.VerifyingContractChainId, tt.opts.VerifyingContractAddress) require.Equal(t, true, ok) ctrl.Finish() }) diff --git a/pkg/services/did.go b/pkg/services/did.go index e2fa29a..90b85a3 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -26,8 +26,10 @@ type DidDocumentServices struct { } type ResolverOpts struct { - State *big.Int - GistRoot *big.Int + State *big.Int + GistRoot *big.Int + VerifyingContractChainId *int + VerifyingContractAddress string } func NewDidDocumentServices(resolvers *ResolverRegistry, registry *ens.Registry) *DidDocumentServices { @@ -140,8 +142,15 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op if identityState.GistInfo != nil { gistInfoRoot = identityState.GistInfo.Root.String() } - - eip712TypedData, err := resolver.TypedData(*userDID, stateInfoState, gistInfoRoot, walletAddress) + verifyingContractChainId := 0 + if opts.VerifyingContractChainId == nil { + return nil, errors.New("error verifying contract chainId is not set") + } + verifyingContractChainId = *opts.VerifyingContractChainId + if opts.VerifyingContractAddress == "" { + return nil, errors.New("error verifying contract address is not set") + } + eip712TypedData, err := resolver.TypedData(verifyingContractChainId, opts.VerifyingContractAddress, *userDID, stateInfoState, gistInfoRoot, walletAddress) if err != nil { return nil, fmt.Errorf("invalid typed data: %v", err) } diff --git a/pkg/services/registry.go b/pkg/services/registry.go index 72be8ac..a890581 100644 --- a/pkg/services/registry.go +++ b/pkg/services/registry.go @@ -98,7 +98,7 @@ type Resolver interface { ResolveGist(ctx context.Context, opts *ResolverOpts) (*GistInfo, error) BlockchainID() string WalletAddress() (string, error) - TypedData(did w3c.DID, state string, gistRoot string, walletAddress string) (apitypes.TypedData, error) + TypedData(verifyingContractChainId int, verifyingContractAddress string, did w3c.DID, state string, gistRoot string, walletAddress string) (apitypes.TypedData, error) } type ResolverRegistry map[string]Resolver From 9fbde46bf68e53d2154fdfc29508f39662422db7 Mon Sep 17 00:00:00 2001 From: daveroga Date: Thu, 18 Jul 2024 18:06:35 +0200 Subject: [PATCH 06/18] add timestamps to signature --- pkg/document/proof_test.go | 34 ++++++++-- pkg/services/blockchain/eth/resolver.go | 71 ++++++++++++-------- pkg/services/blockchain/eth/resolver_test.go | 49 +++++++++----- pkg/services/did.go | 17 ++--- pkg/services/registry.go | 7 +- 5 files changed, 113 insertions(+), 65 deletions(-) diff --git a/pkg/document/proof_test.go b/pkg/document/proof_test.go index 096506d..c5d7b04 100644 --- a/pkg/document/proof_test.go +++ b/pkg/document/proof_test.go @@ -28,7 +28,11 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { "IdentityState": [ { "name": "from", "type": "address" }, { "name": "state", "type": "uint256" }, + { "name": "stateCreatedAtTimestamp", "type": "uint256" }, + { "name": "stateReplacedAtTimestamp", "type": "uint256" }, { "name": "gistRoot", "type": "uint256" }, + { "name": "gistRootCreatedAtTimestamp", "type": "uint256" }, + { "name": "gistRootReplacedAtTimestamp", "type": "uint256" }, { "name": "identity", "type": "uint256" } ] }, @@ -41,9 +45,13 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { }, "message": { "from": "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7", - "gistRoot": "555", - "identity": "19090607534999372304474213543962416547920895595808567155882840509226423042", - "state": "444" + "state": "444", + "stateCreatedAtTimestamp": "0", + "stateReplacedAtTimestamp": "0", + "gistRoot": "555", + "gistRootCreatedAtTimestamp": "0", + "gistRootReplacedAtTimestamp": "0", + "identity": "19090607534999372304474213543962416547920895595808567155882840509226423042" } } }` @@ -57,7 +65,11 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { "IdentityState": []apitypes.Type{ {Name: "from", Type: "address"}, {Name: "state", Type: "uint256"}, + {Name: "stateCreatedAtTimestamp", Type: "uint256"}, + {Name: "stateReplacedAtTimestamp", Type: "uint256"}, {Name: "gistRoot", Type: "uint256"}, + {Name: "gistRootCreatedAtTimestamp", Type: "uint256"}, + {Name: "gistRootReplacedAtTimestamp", Type: "uint256"}, {Name: "identity", Type: "uint256"}, }, "EIP712Domain": []apitypes.Type{ @@ -71,6 +83,10 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { var primaryType = "IdentityState" walletAddress := "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7" state := "444" + stateCreatedAtTimestamp := "0" + stateReplacedAtTimestamp := "0" + gistRootCreatedAtTimestamp := "0" + gistRootReplacedAtTimestamp := "0" gistRoot := "555" identity := "19090607534999372304474213543962416547920895595808567155882840509226423042" chainID := 1 @@ -91,10 +107,14 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { VerifyingContract: "0x0000000000000000000000000000000000000000", }, Message: apitypes.TypedDataMessage{ - "from": walletAddress, - "state": state, - "gistRoot": gistRoot, - "identity": identity, + "from": walletAddress, + "state": state, + "stateCreatedAtTimestamp": stateCreatedAtTimestamp, + "stateReplacedAtTimestamp": stateReplacedAtTimestamp, + "gistRoot": gistRoot, + "gistRootCreatedAtTimestamp": gistRootCreatedAtTimestamp, + "gistRootReplacedAtTimestamp": gistRootReplacedAtTimestamp, + "identity": identity, }, }, } diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 16eef98..668404b 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -55,7 +55,11 @@ var apiTypes = apitypes.Types{ "IdentityState": []apitypes.Type{ {Name: "from", Type: "address"}, {Name: "state", Type: "uint256"}, + {Name: "stateCreatedAtTimestamp", Type: "uint256"}, + {Name: "stateReplacedAtTimestamp", Type: "uint256"}, {Name: "gistRoot", Type: "uint256"}, + {Name: "gistRootCreatedAtTimestamp", Type: "uint256"}, + {Name: "gistRootReplacedAtTimestamp", Type: "uint256"}, {Name: "identity", Type: "uint256"}, }, "EIP712Domain": []apitypes.Type{ @@ -177,12 +181,8 @@ func (r *Resolver) Resolve( stateInfo, gistInfo, err = r.resolveLatest(ctx, userID) } - stateInfoState := "" - gistInfoRoot := "" - identityState := services.IdentityState{} if stateInfo != nil { - stateInfoState = stateInfo.State.String() identityState.StateInfo = &services.StateInfo{ ID: did, State: stateInfo.State, @@ -194,7 +194,6 @@ func (r *Resolver) Resolve( } } if gistInfo != nil { - gistInfoRoot = gistInfo.Root.String() identityState.GistInfo = &services.GistInfo{ Root: gistInfo.Root, ReplacedByRoot: gistInfo.ReplacedByRoot, @@ -207,15 +206,18 @@ func (r *Resolver) Resolve( signature := "" if r.walletKey != "" { - verifyingContractChainId := 0 if opts.VerifyingContractChainId == nil { return services.IdentityState{}, errors.New("error verifying contract chainId is not set") } - verifyingContractChainId = *opts.VerifyingContractChainId if opts.VerifyingContractAddress == "" { return services.IdentityState{}, errors.New("error verifying contract address is not set") } - signature, err = r.signTypedData(verifyingContractChainId, opts.VerifyingContractAddress, did, stateInfoState, gistInfoRoot) + verifyingContract := services.VerifyingContract{ + ChainId: *opts.VerifyingContractChainId, + Address: opts.VerifyingContractAddress, + } + + signature, err = r.signTypedData(verifyingContract, did, identityState) if err != nil { return services.IdentityState{}, err } @@ -232,8 +234,7 @@ func (r *Resolver) Resolve( func (r *Resolver) VerifyIdentityState( identityState services.IdentityState, did w3c.DID, - verifyingContractChainId int, - verifyingContractAddress string, + verifyingContract services.VerifyingContract, ) (bool, error) { privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { @@ -247,16 +248,8 @@ func (r *Resolver) VerifyIdentityState( } walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) - stateInfoState := "" - gistInfoRoot := "" - if identityState.StateInfo != nil { - stateInfoState = identityState.StateInfo.State.String() - } - if identityState.GistInfo != nil { - gistInfoRoot = identityState.GistInfo.Root.String() - } - typedData, err := r.TypedData(verifyingContractChainId, verifyingContractAddress, did, stateInfoState, gistInfoRoot, walletAddress.String()) + typedData, err := r.TypedData(verifyingContract, did, identityState, walletAddress.String()) if err != nil { return false, err } @@ -265,7 +258,7 @@ func (r *Resolver) VerifyIdentityState( return r.verifyTypedData(authData) } -func (r *Resolver) TypedData(verifyingContractChainId int, verifyingContractAddress string, did w3c.DID, state string, gistRoot string, walletAddress string) (apitypes.TypedData, error) { +func (r *Resolver) TypedData(verifyingContract services.VerifyingContract, did w3c.DID, identityState services.IdentityState, walletAddress string) (apitypes.TypedData, error) { userID, err := core.IDFromDID(did) if err != nil { return apitypes.TypedData{}, @@ -273,27 +266,49 @@ func (r *Resolver) TypedData(verifyingContractChainId int, verifyingContractAddr } identity := userID.BigInt().String() + stateInfoState := "0" + stateInfoCreatedAtTimestamp := "0" + stateInfoReplacedAtTimestamp := "0" + + if identityState.StateInfo != nil { + stateInfoState = identityState.StateInfo.State.String() + stateInfoCreatedAtTimestamp = identityState.StateInfo.CreatedAtTimestamp.String() + stateInfoReplacedAtTimestamp = identityState.StateInfo.ReplacedAtTimestamp.String() + } + gistInfoRoot := "0" + gistInfoCreatedAtTimestamp := "0" + gistInfoReplacedAtTimestamp := "0" + if identityState.GistInfo != nil { + gistInfoRoot = identityState.GistInfo.Root.String() + gistInfoCreatedAtTimestamp = identityState.GistInfo.CreatedAtTimestamp.String() + gistInfoReplacedAtTimestamp = identityState.GistInfo.ReplacedAtTimestamp.String() + } + typedData := apitypes.TypedData{ Types: apiTypes, PrimaryType: primaryType, Domain: apitypes.TypedDataDomain{ Name: "StateInfo", Version: "1", - ChainId: math.NewHexOrDecimal256(int64(verifyingContractChainId)), - VerifyingContract: verifyingContractAddress, + ChainId: math.NewHexOrDecimal256(int64(verifyingContract.ChainId)), + VerifyingContract: verifyingContract.Address, }, Message: apitypes.TypedDataMessage{ - "from": walletAddress, - "state": state, - "gistRoot": gistRoot, - "identity": identity, + "from": walletAddress, + "state": stateInfoState, + "stateCreatedAtTimestamp": stateInfoCreatedAtTimestamp, + "stateReplacedAtTimestamp": stateInfoReplacedAtTimestamp, + "gistRoot": gistInfoRoot, + "gistRootCreatedAtTimestamp": gistInfoCreatedAtTimestamp, + "gistRootReplacedAtTimestamp": gistInfoReplacedAtTimestamp, + "identity": identity, }, } return typedData, nil } -func (r *Resolver) signTypedData(verifyingContractChainId int, verifyingContractAddress string, did w3c.DID, state string, gistRoot string) (string, error) { +func (r *Resolver) signTypedData(verifyingContract services.VerifyingContract, did w3c.DID, identityState services.IdentityState) (string, error) { privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { return "", err @@ -307,7 +322,7 @@ func (r *Resolver) signTypedData(verifyingContractChainId int, verifyingContract walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) - typedData, err := r.TypedData(verifyingContractChainId, verifyingContractAddress, did, state, gistRoot, walletAddress.String()) + typedData, err := r.TypedData(verifyingContract, did, identityState, walletAddress.String()) if err != nil { return "", errors.New("error getting typed data for signing") } diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index 9d81b41..7b20670 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -231,20 +231,24 @@ func TestResolveSignature_Success(t *testing.T) { } userID, _ := core.IDFromDID(*userDID) c.EXPECT().GetGISTProofByRoot(gomock.Any(), userID.BigInt(), big.NewInt(1)).Return(proof, nil) - gistInfo := abi.IStateGistRootInfo{Root: big.NewInt(555)} + gistInfo := abi.IStateGistRootInfo{Root: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetGISTRootInfo(gomock.Any(), big.NewInt(4)).Return(gistInfo, nil) - stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(444)} + stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(444), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoByIdAndState(gomock.Any(), gomock.Any(), big.NewInt(5)).Return(stateInfo, nil) }, expectedIdentityState: services.IdentityState{ StateInfo: &services.StateInfo{ - ID: *userDID, - State: big.NewInt(444), + ID: *userDID, + State: big.NewInt(444), + CreatedAtTimestamp: big.NewInt(0), + ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: &services.GistInfo{ - Root: big.NewInt(555), + Root: big.NewInt(555), + CreatedAtTimestamp: big.NewInt(0), + ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0x028ca69378ed198806eecebc722d1bfcf8fb5ca9232274f2403c2d6b4aa3199902555c672c474faec318de2d6974898d542f18f99f884000a22f29d0c2956d291c", + Signature: "0x840efe43812a09ea67648fa3fca8d148dab883ceed81eb484e79561f05522a0012bdff6a3119b23a99e128481f6ffde1ce8960b3d7968d34a513539112071ec61c", }, }, { @@ -257,16 +261,18 @@ func TestResolveSignature_Success(t *testing.T) { userDID: userDID, contractMock: func(c *cm.MockStateContract) { userID, _ := core.IDFromDID(*userDID) - res := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555)} + res := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoByIdAndState(gomock.Any(), gomock.Any(), big.NewInt(1)).Return(res, nil) }, expectedIdentityState: services.IdentityState{ StateInfo: &services.StateInfo{ - ID: *userDID, - State: big.NewInt(555), + ID: *userDID, + State: big.NewInt(555), + CreatedAtTimestamp: big.NewInt(0), + ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: nil, - Signature: "0xb23932bd8f5fc4674583b41ceade5aeb6113ea22b3f330e4deaaa432dfed9ab853dac55f531abd90a8c89b573444aeb974305c3a8aac3bc201531aad34383fbb1c", + Signature: "0x5f411887c018ed7438f3887167b23464e8807078d163185e043f7b3117a3b59106a5fae670451c17f43cdc9842c5abccc3210d3b7e7a4627c8ab840c0e480d711c", }, }, { @@ -280,20 +286,24 @@ func TestResolveSignature_Success(t *testing.T) { userID, _ := core.IDFromDID(*userDID) latestGist := big.NewInt(100) c.EXPECT().GetGISTRoot(gomock.Any()).Return(latestGist, nil) - latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400)} + latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetGISTRootInfo(gomock.Any(), latestGist).Return(latestGistInfo, nil) - stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555)} + stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoById(gomock.Any(), userID.BigInt()).Return(stateInfo, nil) }, expectedIdentityState: services.IdentityState{ StateInfo: &services.StateInfo{ - ID: *userDID, - State: big.NewInt(555), + ID: *userDID, + State: big.NewInt(555), + CreatedAtTimestamp: big.NewInt(0), + ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: &services.GistInfo{ - Root: big.NewInt(400), + Root: big.NewInt(400), + CreatedAtTimestamp: big.NewInt(0), + ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0x5a9ea69f9311ac800a3fc2375cf6fa4d4646b5b2b55219f934755177c93d367a152e4ab7585600598f280485c41471a782dc6ef3e1fd235bd48e4441446ec24d1b", + Signature: "0xee0ba8b277b71b4b3e79c668d5e3de169e5e72f92b3bb4e8637e570ca6c810bd5684d01b9a9b7fbbead7528040715b77d9a8177aa3de72a589851cd252dd6a111b", }, }, } @@ -314,7 +324,12 @@ func TestResolveSignature_Success(t *testing.T) { require.NoError(t, err) require.Equal(t, tt.expectedIdentityState, identityState) - ok, _ := resolver.VerifyIdentityState(identityState, *tt.userDID, *tt.opts.VerifyingContractChainId, tt.opts.VerifyingContractAddress) + verifyingContract := services.VerifyingContract{ + ChainId: *tt.opts.VerifyingContractChainId, + Address: tt.opts.VerifyingContractAddress, + } + + ok, _ := resolver.VerifyIdentityState(identityState, *tt.userDID, verifyingContract) require.Equal(t, true, ok) ctrl.Finish() }) diff --git a/pkg/services/did.go b/pkg/services/did.go index 90b85a3..a707f19 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -133,24 +133,17 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op walletAddress, err := resolver.WalletAddress() if err == nil { - stateInfoState := "" - gistInfoRoot := "" - if identityState.StateInfo != nil { - stateInfoState = identityState.StateInfo.State.String() - } - - if identityState.GistInfo != nil { - gistInfoRoot = identityState.GistInfo.Root.String() - } - verifyingContractChainId := 0 if opts.VerifyingContractChainId == nil { return nil, errors.New("error verifying contract chainId is not set") } - verifyingContractChainId = *opts.VerifyingContractChainId if opts.VerifyingContractAddress == "" { return nil, errors.New("error verifying contract address is not set") } - eip712TypedData, err := resolver.TypedData(verifyingContractChainId, opts.VerifyingContractAddress, *userDID, stateInfoState, gistInfoRoot, walletAddress) + verifyingContract := VerifyingContract{ + ChainId: *opts.VerifyingContractChainId, + Address: opts.VerifyingContractAddress, + } + eip712TypedData, err := resolver.TypedData(verifyingContract, *userDID, identityState, walletAddress) if err != nil { return nil, fmt.Errorf("invalid typed data: %v", err) } diff --git a/pkg/services/registry.go b/pkg/services/registry.go index a890581..46fc6d1 100644 --- a/pkg/services/registry.go +++ b/pkg/services/registry.go @@ -35,6 +35,11 @@ type StateInfo struct { ReplacedAtBlock *big.Int } +type VerifyingContract struct { + ChainId int + Address string +} + func (si *StateInfo) ToDidRepresentation() (*verifiable.StateInfo, error) { if si == nil { return nil, nil @@ -98,7 +103,7 @@ type Resolver interface { ResolveGist(ctx context.Context, opts *ResolverOpts) (*GistInfo, error) BlockchainID() string WalletAddress() (string, error) - TypedData(verifyingContractChainId int, verifyingContractAddress string, did w3c.DID, state string, gistRoot string, walletAddress string) (apitypes.TypedData, error) + TypedData(verifyingContract VerifyingContract, did w3c.DID, identityState IdentityState, walletAddress string) (apitypes.TypedData, error) } type ResolverRegistry map[string]Resolver From 9735733cafa2500324b5101782f1b951850bd6e2 Mon Sep 17 00:00:00 2001 From: daveroga Date: Thu, 18 Jul 2024 20:30:13 +0200 Subject: [PATCH 07/18] resolve only gist if 0s in did --- pkg/services/blockchain/eth/resolver.go | 62 ++++++++++++++------ pkg/services/blockchain/eth/resolver_test.go | 25 ++++++++ pkg/services/did.go | 40 ++++++++----- 3 files changed, 94 insertions(+), 33 deletions(-) diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 668404b..ee7bb9a 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -166,19 +166,31 @@ func (r *Resolver) Resolve( err error ) - userID, err := core.IDFromDID(did) - if err != nil { - return services.IdentityState{}, - fmt.Errorf("invalid did format for did '%s': %v", did, err) - } + if did.IDStrings[2] == "000000000000000000000000000000000000000000" { + if opts.GistRoot == nil { + return services.IdentityState{}, + errors.New("options GistRoot is required for root only did") + } + stateInfo, gistInfo, err = r.resolveGistRootOnly(ctx, opts.GistRoot) + } else { + userID, err := core.IDFromDID(did) + if err != nil { + return services.IdentityState{}, + fmt.Errorf("invalid did format for did '%s': %v", did, err) + } - switch { - case opts.GistRoot != nil: - stateInfo, gistInfo, err = r.resolveStateByGistRoot(ctx, userID, opts.GistRoot) - case opts.State != nil: - stateInfo, err = r.resolveState(ctx, userID, opts.State) - default: - stateInfo, gistInfo, err = r.resolveLatest(ctx, userID) + switch { + case opts.GistRoot != nil: + stateInfo, gistInfo, err = r.resolveStateByGistRoot(ctx, userID, opts.GistRoot) + case opts.State != nil: + stateInfo, err = r.resolveState(ctx, userID, opts.State) + default: + stateInfo, gistInfo, err = r.resolveLatest(ctx, userID) + } + + if err != nil && err.Error() != "identity not found" { + return services.IdentityState{}, err + } } identityState := services.IdentityState{} @@ -259,13 +271,15 @@ func (r *Resolver) VerifyIdentityState( } func (r *Resolver) TypedData(verifyingContract services.VerifyingContract, did w3c.DID, identityState services.IdentityState, walletAddress string) (apitypes.TypedData, error) { - userID, err := core.IDFromDID(did) - if err != nil { - return apitypes.TypedData{}, - fmt.Errorf("invalid did format for did '%s': %v", did, err) + identity := "0" + if did.IDStrings[2] != "000000000000000000000000000000000000000000" { + userID, err := core.IDFromDID(did) + if err != nil { + return apitypes.TypedData{}, + fmt.Errorf("invalid did format for did '%s': %v", did, err) + } + identity = userID.BigInt().String() } - identity := userID.BigInt().String() - stateInfoState := "0" stateInfoCreatedAtTimestamp := "0" stateInfoReplacedAtTimestamp := "0" @@ -468,6 +482,18 @@ func (r *Resolver) resolveStateByGistRoot( return &stateInfo, &gistInfo, verifyContractState(id, stateInfo) } +func (r *Resolver) resolveGistRootOnly( + ctx context.Context, + gistRoot *big.Int, +) (*abi.IStateStateInfo, *abi.IStateGistRootInfo, error) { + gistInfo, err := r.state.GetGISTRootInfo(&bind.CallOpts{Context: ctx}, gistRoot) + if err = notFoundErr(err); err != nil { + return nil, nil, err + } + + return nil, &gistInfo, nil +} + func verifyContractState(id core.ID, state abi.IStateStateInfo) error { if state.Id.Cmp(id.BigInt()) != 0 { return fmt.Errorf("expected id '%s' not equal id '%s' from contract", diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index 7b20670..fbecbe2 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -208,6 +208,8 @@ func TestNotFoundErr(t *testing.T) { func TestResolveSignature_Success(t *testing.T) { verifyingContractChainId := new(int) *verifyingContractChainId = 1 + userEmptyDID, _ := w3c.ParseDID("did:polygonid:polygon:amoy:000000000000000000000000000000000000000000") + tests := []struct { name string opts *services.ResolverOpts @@ -306,6 +308,29 @@ func TestResolveSignature_Success(t *testing.T) { Signature: "0xee0ba8b277b71b4b3e79c668d5e3de169e5e72f92b3bb4e8637e570ca6c810bd5684d01b9a9b7fbbead7528040715b77d9a8177aa3de72a589851cd252dd6a111b", }, }, + { + name: "resolve only gist", + opts: &services.ResolverOpts{ + GistRoot: big.NewInt(400), + VerifyingContractChainId: verifyingContractChainId, + VerifyingContractAddress: "0x0000000000000000000000000000000000000000", + }, + userDID: userEmptyDID, + contractMock: func(c *cm.MockStateContract) { + latestGist := big.NewInt(400) + latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} + c.EXPECT().GetGISTRootInfo(gomock.Any(), latestGist).Return(latestGistInfo, nil) + }, + expectedIdentityState: services.IdentityState{ + StateInfo: nil, + GistInfo: &services.GistInfo{ + Root: big.NewInt(400), + CreatedAtTimestamp: big.NewInt(0), + ReplacedAtTimestamp: big.NewInt(0), + }, + Signature: "0x20cbaf4cd93fbe19aafe4fb0c76eaa1828fb1d7918f2afdebd9fe0db8269c81d291ea72edecce1c038ce89f0ba13bb717779739b885b0d11d15a8045f701f3071b", + }, + }, } mnemonic := "rib satisfy drastic trigger trial exclude raccoon wedding then gaze fire hero" diff --git a/pkg/services/did.go b/pkg/services/did.go index a707f19..16b5010 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -48,25 +48,35 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op return errResolution, err } - userID, err := core.IDFromDID(*userDID) - errResolution, err = expectedError(err) - if err != nil { - return errResolution, err - } + blockchain := "" + network := "" + userID := core.ID{} + if userDID.IDStrings[2] == "000000000000000000000000000000000000000000" { + blockchain = userDID.IDStrings[0] + network = userDID.IDStrings[1] + } else { + userID, err := core.IDFromDID(*userDID) + errResolution, err = expectedError(err) + if err != nil { + return errResolution, err + } - b, err := core.BlockchainFromID(userID) - errResolution, err = expectedError(err) - if err != nil { - return errResolution, err - } + b, err := core.BlockchainFromID(userID) + errResolution, err = expectedError(err) + if err != nil { + return errResolution, err + } - n, err := core.NetworkIDFromID(userID) - errResolution, err = expectedError(err) - if err != nil { - return errResolution, err + n, err := core.NetworkIDFromID(userID) + errResolution, err = expectedError(err) + if err != nil { + return errResolution, err + } + blockchain = string(b) + network = string(n) } - resolver, err := d.resolvers.GetResolverByNetwork(string(b), string(n)) + resolver, err := d.resolvers.GetResolverByNetwork(blockchain, network) errResolution, err = expectedError(err) if err != nil { return errResolution, err From 156795f7d9eacbf93d9048cff5496a2ad3c0fc94 Mon Sep 17 00:00:00 2001 From: daveroga Date: Fri, 19 Jul 2024 08:21:32 +0200 Subject: [PATCH 08/18] optionally return signature if passing verifying contract params --- pkg/services/did.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pkg/services/did.go b/pkg/services/did.go index 16b5010..34ebd0f 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -142,13 +142,7 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op walletAddress, err := resolver.WalletAddress() - if err == nil { - if opts.VerifyingContractChainId == nil { - return nil, errors.New("error verifying contract chainId is not set") - } - if opts.VerifyingContractAddress == "" { - return nil, errors.New("error verifying contract address is not set") - } + if err == nil && opts.VerifyingContractChainId != nil && opts.VerifyingContractAddress != "" { verifyingContract := VerifyingContract{ ChainId: *opts.VerifyingContractChainId, Address: opts.VerifyingContractAddress, From 3782f58604826315844dd734a28de9b2cb528496 Mon Sep 17 00:00:00 2001 From: daveroga Date: Fri, 19 Jul 2024 10:33:35 +0200 Subject: [PATCH 09/18] fix issue ethereum address --- pkg/services/blockchain/eth/resolver.go | 11 +---------- pkg/services/did.go | 4 ++-- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index ee7bb9a..14b02b9 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -217,13 +217,7 @@ func (r *Resolver) Resolve( } signature := "" - if r.walletKey != "" { - if opts.VerifyingContractChainId == nil { - return services.IdentityState{}, errors.New("error verifying contract chainId is not set") - } - if opts.VerifyingContractAddress == "" { - return services.IdentityState{}, errors.New("error verifying contract address is not set") - } + if r.walletKey != "" && opts.VerifyingContractChainId != nil && opts.VerifyingContractAddress != "" { verifyingContract := services.VerifyingContract{ ChainId: *opts.VerifyingContractChainId, Address: opts.VerifyingContractAddress, @@ -237,9 +231,6 @@ func (r *Resolver) Resolve( identityState.Signature = signature - // verified, _ := r.VerifyIdentityState(identityState, did) - // log.Println("VERIFIED:", verified) - return identityState, err } diff --git a/pkg/services/did.go b/pkg/services/did.go index 34ebd0f..8bf17bd 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -55,7 +55,7 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op blockchain = userDID.IDStrings[0] network = userDID.IDStrings[1] } else { - userID, err := core.IDFromDID(*userDID) + userID, err = core.IDFromDID(*userDID) errResolution, err = expectedError(err) if err != nil { return errResolution, err @@ -110,7 +110,7 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op chainIDStateAddress := resolver.BlockchainID() - if err == nil { + if err == nil && userDID.IDStrings[2] != "000000000000000000000000000000000000000000" { addressString := fmt.Sprintf("%x", addr) blockchainAccountID := fmt.Sprintf("eip155:%s:0x%s", strings.Split(chainIDStateAddress, ":")[0], addressString) didResolution.DidDocument.VerificationMethod = append( From 798b8db01722a595e9847057791fcaf75a5b8f4f Mon Sep 17 00:00:00 2001 From: daveroga Date: Fri, 19 Jul 2024 19:07:00 +0200 Subject: [PATCH 10/18] add timestamp to message --- pkg/document/proof_test.go | 5 +++++ pkg/services/blockchain/eth/resolver.go | 12 ++++++++++ pkg/services/blockchain/eth/resolver_test.go | 23 +++++++++++++++----- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/pkg/document/proof_test.go b/pkg/document/proof_test.go index c5d7b04..a213862 100644 --- a/pkg/document/proof_test.go +++ b/pkg/document/proof_test.go @@ -27,6 +27,7 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { ], "IdentityState": [ { "name": "from", "type": "address" }, + { "name": "timestamp", "type": "uint256" }, { "name": "state", "type": "uint256" }, { "name": "stateCreatedAtTimestamp", "type": "uint256" }, { "name": "stateReplacedAtTimestamp", "type": "uint256" }, @@ -45,6 +46,7 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { }, "message": { "from": "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7", + "timestamp": "0", "state": "444", "stateCreatedAtTimestamp": "0", "stateReplacedAtTimestamp": "0", @@ -64,6 +66,7 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { var apiTypes = apitypes.Types{ "IdentityState": []apitypes.Type{ {Name: "from", Type: "address"}, + {Name: "timestamp", Type: "uint256"}, {Name: "state", Type: "uint256"}, {Name: "stateCreatedAtTimestamp", Type: "uint256"}, {Name: "stateReplacedAtTimestamp", Type: "uint256"}, @@ -87,6 +90,7 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { stateReplacedAtTimestamp := "0" gistRootCreatedAtTimestamp := "0" gistRootReplacedAtTimestamp := "0" + timestamp := "0" gistRoot := "555" identity := "19090607534999372304474213543962416547920895595808567155882840509226423042" chainID := 1 @@ -108,6 +112,7 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { }, Message: apitypes.TypedDataMessage{ "from": walletAddress, + "timestamp": timestamp, "state": state, "stateCreatedAtTimestamp": stateCreatedAtTimestamp, "stateReplacedAtTimestamp": stateReplacedAtTimestamp, diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 14b02b9..814cb9d 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -8,6 +8,8 @@ import ( "errors" "fmt" "math/big" + "strconv" + "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -54,6 +56,7 @@ var ( var apiTypes = apitypes.Types{ "IdentityState": []apitypes.Type{ {Name: "from", Type: "address"}, + {Name: "timestamp", Type: "uint256"}, {Name: "state", Type: "uint256"}, {Name: "stateCreatedAtTimestamp", Type: "uint256"}, {Name: "stateReplacedAtTimestamp", Type: "uint256"}, @@ -72,6 +75,8 @@ var apiTypes = apitypes.Types{ var primaryType = "IdentityState" +var TimeStamp = TimeStampFn + // NewResolver create new ethereum resolver. func NewResolver(url, address, walletKey string) (*Resolver, error) { c, err := ethclient.Dial(url) @@ -261,6 +266,11 @@ func (r *Resolver) VerifyIdentityState( return r.verifyTypedData(authData) } +func TimeStampFn() string { + timestamp := strconv.FormatInt(time.Now().UTC().Unix(), 10) + return timestamp +} + func (r *Resolver) TypedData(verifyingContract services.VerifyingContract, did w3c.DID, identityState services.IdentityState, walletAddress string) (apitypes.TypedData, error) { identity := "0" if did.IDStrings[2] != "000000000000000000000000000000000000000000" { @@ -289,6 +299,7 @@ func (r *Resolver) TypedData(verifyingContract services.VerifyingContract, did w gistInfoReplacedAtTimestamp = identityState.GistInfo.ReplacedAtTimestamp.String() } + timestamp := TimeStamp() typedData := apitypes.TypedData{ Types: apiTypes, PrimaryType: primaryType, @@ -300,6 +311,7 @@ func (r *Resolver) TypedData(verifyingContract services.VerifyingContract, did w }, Message: apitypes.TypedDataMessage{ "from": walletAddress, + "timestamp": timestamp, "state": stateInfoState, "stateCreatedAtTimestamp": stateInfoCreatedAtTimestamp, "stateReplacedAtTimestamp": stateInfoReplacedAtTimestamp, diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index fbecbe2..652d421 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -215,6 +215,7 @@ func TestResolveSignature_Success(t *testing.T) { opts *services.ResolverOpts userDID *w3c.DID contractMock func(c *cm.MockStateContract) + timeStamp func() string expectedIdentityState services.IdentityState }{ { @@ -238,6 +239,9 @@ func TestResolveSignature_Success(t *testing.T) { stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(444), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoByIdAndState(gomock.Any(), gomock.Any(), big.NewInt(5)).Return(stateInfo, nil) }, + timeStamp: func() string { + return "0" + }, expectedIdentityState: services.IdentityState{ StateInfo: &services.StateInfo{ ID: *userDID, @@ -250,7 +254,7 @@ func TestResolveSignature_Success(t *testing.T) { CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0x840efe43812a09ea67648fa3fca8d148dab883ceed81eb484e79561f05522a0012bdff6a3119b23a99e128481f6ffde1ce8960b3d7968d34a513539112071ec61c", + Signature: "0xb35a80bf24a76c1f0b1d2026af586c5a424d456eaa496031be8ea36724f0b4121dea6259ebb126f4473698980311bda48678f220da4149975636d00c5b3a716b1b", }, }, { @@ -266,6 +270,9 @@ func TestResolveSignature_Success(t *testing.T) { res := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoByIdAndState(gomock.Any(), gomock.Any(), big.NewInt(1)).Return(res, nil) }, + timeStamp: func() string { + return "0" + }, expectedIdentityState: services.IdentityState{ StateInfo: &services.StateInfo{ ID: *userDID, @@ -274,7 +281,7 @@ func TestResolveSignature_Success(t *testing.T) { ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: nil, - Signature: "0x5f411887c018ed7438f3887167b23464e8807078d163185e043f7b3117a3b59106a5fae670451c17f43cdc9842c5abccc3210d3b7e7a4627c8ab840c0e480d711c", + Signature: "0x29c02ac82784594f9eca4194502ce3514414b02ac359277991f4af6cfcef1965497b07d288a841bd8a5f45bd8859e8259a6c19f722fe66707f1ebb160a82bcbe1b", }, }, { @@ -293,6 +300,9 @@ func TestResolveSignature_Success(t *testing.T) { stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoById(gomock.Any(), userID.BigInt()).Return(stateInfo, nil) }, + timeStamp: func() string { + return "0" + }, expectedIdentityState: services.IdentityState{ StateInfo: &services.StateInfo{ ID: *userDID, @@ -305,7 +315,7 @@ func TestResolveSignature_Success(t *testing.T) { CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0xee0ba8b277b71b4b3e79c668d5e3de169e5e72f92b3bb4e8637e570ca6c810bd5684d01b9a9b7fbbead7528040715b77d9a8177aa3de72a589851cd252dd6a111b", + Signature: "0x01645122b7895740b445a8b2a149f853948af73f6ecec4061322ceaa5df45ce451ea151e8aec2c30bc30ef9175788fcd3e451d3faad483c071f81950b5984fda1c", }, }, { @@ -321,6 +331,9 @@ func TestResolveSignature_Success(t *testing.T) { latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetGISTRootInfo(gomock.Any(), latestGist).Return(latestGistInfo, nil) }, + timeStamp: func() string { + return "0" + }, expectedIdentityState: services.IdentityState{ StateInfo: nil, GistInfo: &services.GistInfo{ @@ -328,7 +341,7 @@ func TestResolveSignature_Success(t *testing.T) { CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0x20cbaf4cd93fbe19aafe4fb0c76eaa1828fb1d7918f2afdebd9fe0db8269c81d291ea72edecce1c038ce89f0ba13bb717779739b885b0d11d15a8045f701f3071b", + Signature: "0xe3c17d6d39f96bc16738ce69897e5770abde25bb44e6b987b1279034820135f377350456a314ba39bb9c6292cc06d74d19cf577b0a31bf82de454ea30be1615b1b", }, }, } @@ -344,11 +357,11 @@ func TestResolveSignature_Success(t *testing.T) { ctrl := gomock.NewController(t) stateContract := cm.NewMockStateContract(ctrl) tt.contractMock(stateContract) + TimeStamp = tt.timeStamp resolver := Resolver{state: stateContract, chainID: 1, walletKey: privateKeyHex} identityState, err := resolver.Resolve(context.Background(), *tt.userDID, tt.opts) require.NoError(t, err) require.Equal(t, tt.expectedIdentityState, identityState) - verifyingContract := services.VerifyingContract{ ChainId: *tt.opts.VerifyingContractChainId, Address: tt.opts.VerifyingContractAddress, From 091d4a1f3c5a03189f8bd47d5bb78bb52cf3b7ba Mon Sep 17 00:00:00 2001 From: daveroga Date: Tue, 23 Jul 2024 16:46:03 +0200 Subject: [PATCH 11/18] remove verifying contract params and chainid=0 and verifyingcontract=0x0 --- Dockerfile | 2 +- pkg/app/handler.go | 23 ++++--------- pkg/services/blockchain/eth/resolver.go | 22 +++++-------- pkg/services/blockchain/eth/resolver_test.go | 34 +++++++------------- pkg/services/did.go | 15 +++------ pkg/services/registry.go | 7 +--- 6 files changed, 33 insertions(+), 70 deletions(-) diff --git a/Dockerfile b/Dockerfile index 80d0165..130d0d0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ ## ## Build did driver ## -FROM golang:1.18-alpine as base +FROM golang:1.18-alpine AS base WORKDIR /build diff --git a/pkg/app/handler.go b/pkg/app/handler.go index 0d5d2ea..8d27e6a 100644 --- a/pkg/app/handler.go +++ b/pkg/app/handler.go @@ -5,8 +5,6 @@ import ( "fmt" "log" "net/http" - "regexp" - "strconv" "strings" "github.com/iden3/driver-did-polygonid/pkg/services" @@ -25,8 +23,7 @@ func (d *DidDocumentHandler) Get(w http.ResponseWriter, r *http.Request) { opts, err := getResolverOpts( r.URL.Query().Get("state"), r.URL.Query().Get("gist"), - r.URL.Query().Get("verifyingContractChainId"), - r.URL.Query().Get("verifyingContractAddress"), + r.URL.Query().Get("signature"), ) if err != nil { log.Println("invalid options query:", err) @@ -114,7 +111,7 @@ func (d *DidDocumentHandler) GetGist(w http.ResponseWriter, r *http.Request) { } } -func getResolverOpts(state, gistRoot, verifyingContractChainId, verifyingContractAddress string) (ro services.ResolverOpts, err error) { +func getResolverOpts(state, gistRoot, signature string) (ro services.ResolverOpts, err error) { if state != "" && gistRoot != "" { return ro, errors.New("'state' and 'gist root' cannot be used together") } @@ -132,19 +129,11 @@ func getResolverOpts(state, gistRoot, verifyingContractChainId, verifyingContrac } ro.GistRoot = g.BigInt() } - if verifyingContractChainId != "" { - i, err := strconv.Atoi(verifyingContractChainId) - if err != nil { - return ro, fmt.Errorf("invalid verifying contract chainId format: %v", err) - } - ro.VerifyingContractChainId = &i - } - if verifyingContractAddress != "" { - re := regexp.MustCompile("^0x[0-9a-fA-F]{40}$") - if !re.MatchString(verifyingContractAddress) { - return ro, fmt.Errorf("invalid verifying contract address format: %v", err) + if signature != "" { + if signature != "EthereumEip712Signature2021" { + return ro, fmt.Errorf("not supported signature type %s", signature) } - ro.VerifyingContractAddress = verifyingContractAddress + ro.Signature = signature } return } diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 814cb9d..e463619 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -222,13 +222,8 @@ func (r *Resolver) Resolve( } signature := "" - if r.walletKey != "" && opts.VerifyingContractChainId != nil && opts.VerifyingContractAddress != "" { - verifyingContract := services.VerifyingContract{ - ChainId: *opts.VerifyingContractChainId, - Address: opts.VerifyingContractAddress, - } - - signature, err = r.signTypedData(verifyingContract, did, identityState) + if r.walletKey != "" && opts.Signature != "" { + signature, err = r.signTypedData(did, identityState) if err != nil { return services.IdentityState{}, err } @@ -242,7 +237,6 @@ func (r *Resolver) Resolve( func (r *Resolver) VerifyIdentityState( identityState services.IdentityState, did w3c.DID, - verifyingContract services.VerifyingContract, ) (bool, error) { privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { @@ -257,7 +251,7 @@ func (r *Resolver) VerifyIdentityState( walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) - typedData, err := r.TypedData(verifyingContract, did, identityState, walletAddress.String()) + typedData, err := r.TypedData(did, identityState, walletAddress.String()) if err != nil { return false, err } @@ -271,7 +265,7 @@ func TimeStampFn() string { return timestamp } -func (r *Resolver) TypedData(verifyingContract services.VerifyingContract, did w3c.DID, identityState services.IdentityState, walletAddress string) (apitypes.TypedData, error) { +func (r *Resolver) TypedData(did w3c.DID, identityState services.IdentityState, walletAddress string) (apitypes.TypedData, error) { identity := "0" if did.IDStrings[2] != "000000000000000000000000000000000000000000" { userID, err := core.IDFromDID(did) @@ -306,8 +300,8 @@ func (r *Resolver) TypedData(verifyingContract services.VerifyingContract, did w Domain: apitypes.TypedDataDomain{ Name: "StateInfo", Version: "1", - ChainId: math.NewHexOrDecimal256(int64(verifyingContract.ChainId)), - VerifyingContract: verifyingContract.Address, + ChainId: math.NewHexOrDecimal256(int64(0)), + VerifyingContract: "0x0000000000000000000000000000000000000000", }, Message: apitypes.TypedDataMessage{ "from": walletAddress, @@ -325,7 +319,7 @@ func (r *Resolver) TypedData(verifyingContract services.VerifyingContract, did w return typedData, nil } -func (r *Resolver) signTypedData(verifyingContract services.VerifyingContract, did w3c.DID, identityState services.IdentityState) (string, error) { +func (r *Resolver) signTypedData(did w3c.DID, identityState services.IdentityState) (string, error) { privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { return "", err @@ -339,7 +333,7 @@ func (r *Resolver) signTypedData(verifyingContract services.VerifyingContract, d walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) - typedData, err := r.TypedData(verifyingContract, did, identityState, walletAddress.String()) + typedData, err := r.TypedData(did, identityState, walletAddress.String()) if err != nil { return "", errors.New("error getting typed data for signing") } diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index 652d421..153b15a 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -206,8 +206,6 @@ func TestNotFoundErr(t *testing.T) { } func TestResolveSignature_Success(t *testing.T) { - verifyingContractChainId := new(int) - *verifyingContractChainId = 1 userEmptyDID, _ := w3c.ParseDID("did:polygonid:polygon:amoy:000000000000000000000000000000000000000000") tests := []struct { @@ -221,9 +219,8 @@ func TestResolveSignature_Success(t *testing.T) { { name: "resolve identity state by gist", opts: &services.ResolverOpts{ - GistRoot: big.NewInt(1), - VerifyingContractChainId: verifyingContractChainId, - VerifyingContractAddress: "0x0000000000000000000000000000000000000000", + GistRoot: big.NewInt(1), + Signature: "EthereumEip712Signature2021", }, userDID: userDID, contractMock: func(c *cm.MockStateContract) { @@ -254,15 +251,14 @@ func TestResolveSignature_Success(t *testing.T) { CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0xb35a80bf24a76c1f0b1d2026af586c5a424d456eaa496031be8ea36724f0b4121dea6259ebb126f4473698980311bda48678f220da4149975636d00c5b3a716b1b", + Signature: "0xe63151912749d0cae7fea6a13dda6d54061626cc03a79dac46b6a11b3259c6c335d8266f09eaf070a31c8a23765fb01e3c8bf927f5ab25346f743ae309eabc801c", }, }, { name: "resolve identity state by state", opts: &services.ResolverOpts{ - State: big.NewInt(1), - VerifyingContractChainId: verifyingContractChainId, - VerifyingContractAddress: "0x0000000000000000000000000000000000000000", + State: big.NewInt(1), + Signature: "EthereumEip712Signature2021", }, userDID: userDID, contractMock: func(c *cm.MockStateContract) { @@ -281,14 +277,13 @@ func TestResolveSignature_Success(t *testing.T) { ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: nil, - Signature: "0x29c02ac82784594f9eca4194502ce3514414b02ac359277991f4af6cfcef1965497b07d288a841bd8a5f45bd8859e8259a6c19f722fe66707f1ebb160a82bcbe1b", + Signature: "0x3dce5819f16b5225bbe9ec3ce144b45654119f4cfdff2f9e8f5d33a0fc3790de570dfacdc304ee217b43952c9393425fc45f5abc9e9f7e5b63196479319eb62c1b", }, }, { name: "resolve latest state", opts: &services.ResolverOpts{ - VerifyingContractChainId: verifyingContractChainId, - VerifyingContractAddress: "0x0000000000000000000000000000000000000000", + Signature: "EthereumEip712Signature2021", }, userDID: userDID, contractMock: func(c *cm.MockStateContract) { @@ -315,15 +310,14 @@ func TestResolveSignature_Success(t *testing.T) { CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0x01645122b7895740b445a8b2a149f853948af73f6ecec4061322ceaa5df45ce451ea151e8aec2c30bc30ef9175788fcd3e451d3faad483c071f81950b5984fda1c", + Signature: "0x866206f5be01973be72631fd9931d8ccc7d6e8612f799dc39ff495d1e3a975af7c81c0e4fc13e50f4177fbc637e81ca546ee2906eccf1dfa96687fff05bd49831c", }, }, { name: "resolve only gist", opts: &services.ResolverOpts{ - GistRoot: big.NewInt(400), - VerifyingContractChainId: verifyingContractChainId, - VerifyingContractAddress: "0x0000000000000000000000000000000000000000", + GistRoot: big.NewInt(400), + Signature: "EthereumEip712Signature2021", }, userDID: userEmptyDID, contractMock: func(c *cm.MockStateContract) { @@ -341,7 +335,7 @@ func TestResolveSignature_Success(t *testing.T) { CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0xe3c17d6d39f96bc16738ce69897e5770abde25bb44e6b987b1279034820135f377350456a314ba39bb9c6292cc06d74d19cf577b0a31bf82de454ea30be1615b1b", + Signature: "0xec3a8bd564247bed3c16f719d499e02d4914a8fa10704a8f3dcae75ca393b3ae47c3f147355f5476cb495b8e0463fd128da2795c02bd9420f8071d93652d13b81b", }, }, } @@ -362,12 +356,8 @@ func TestResolveSignature_Success(t *testing.T) { identityState, err := resolver.Resolve(context.Background(), *tt.userDID, tt.opts) require.NoError(t, err) require.Equal(t, tt.expectedIdentityState, identityState) - verifyingContract := services.VerifyingContract{ - ChainId: *tt.opts.VerifyingContractChainId, - Address: tt.opts.VerifyingContractAddress, - } - ok, _ := resolver.VerifyIdentityState(identityState, *tt.userDID, verifyingContract) + ok, _ := resolver.VerifyIdentityState(identityState, *tt.userDID) require.Equal(t, true, ok) ctrl.Finish() }) diff --git a/pkg/services/did.go b/pkg/services/did.go index 8bf17bd..ee2ebdb 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -26,10 +26,9 @@ type DidDocumentServices struct { } type ResolverOpts struct { - State *big.Int - GistRoot *big.Int - VerifyingContractChainId *int - VerifyingContractAddress string + State *big.Int + GistRoot *big.Int + Signature string } func NewDidDocumentServices(resolvers *ResolverRegistry, registry *ens.Registry) *DidDocumentServices { @@ -142,12 +141,8 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op walletAddress, err := resolver.WalletAddress() - if err == nil && opts.VerifyingContractChainId != nil && opts.VerifyingContractAddress != "" { - verifyingContract := VerifyingContract{ - ChainId: *opts.VerifyingContractChainId, - Address: opts.VerifyingContractAddress, - } - eip712TypedData, err := resolver.TypedData(verifyingContract, *userDID, identityState, walletAddress) + if err == nil && opts.Signature != "" { + eip712TypedData, err := resolver.TypedData(*userDID, identityState, walletAddress) if err != nil { return nil, fmt.Errorf("invalid typed data: %v", err) } diff --git a/pkg/services/registry.go b/pkg/services/registry.go index 46fc6d1..c7810b9 100644 --- a/pkg/services/registry.go +++ b/pkg/services/registry.go @@ -35,11 +35,6 @@ type StateInfo struct { ReplacedAtBlock *big.Int } -type VerifyingContract struct { - ChainId int - Address string -} - func (si *StateInfo) ToDidRepresentation() (*verifiable.StateInfo, error) { if si == nil { return nil, nil @@ -103,7 +98,7 @@ type Resolver interface { ResolveGist(ctx context.Context, opts *ResolverOpts) (*GistInfo, error) BlockchainID() string WalletAddress() (string, error) - TypedData(verifyingContract VerifyingContract, did w3c.DID, identityState IdentityState, walletAddress string) (apitypes.TypedData, error) + TypedData(did w3c.DID, identityState IdentityState, walletAddress string) (apitypes.TypedData, error) } type ResolverRegistry map[string]Resolver From 67ced736f2302fc7a7b0f87c7bce5af16407807c Mon Sep 17 00:00:00 2001 From: daveroga Date: Tue, 23 Jul 2024 17:17:10 +0200 Subject: [PATCH 12/18] fix lint errors --- .golangci.yml | 7 ------- pkg/app/handler.go | 2 +- pkg/document/proof.go | 1 + pkg/services/blockchain/eth/resolver.go | 11 ++++++----- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index c547f45..51dba5f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -39,22 +39,15 @@ linters-settings: linters: enable: - bodyclose - - megacheck - revive - govet - unconvert - - megacheck - - structcheck - - gas - gocyclo - dupl - misspell - unparam - - varcheck - - deadcode - typecheck - ineffassign - - varcheck - stylecheck - gochecknoinits - exportloopref diff --git a/pkg/app/handler.go b/pkg/app/handler.go index 8d27e6a..5c2b9a8 100644 --- a/pkg/app/handler.go +++ b/pkg/app/handler.go @@ -97,7 +97,7 @@ func (d *DidDocumentHandler) GetGist(w http.ResponseWriter, r *http.Request) { gistInfo, err := d.DidDocumentService.GetGist(r.Context(), chain, networkid, nil) if errors.Is(err, services.ErrNetworkIsNotSupported) { w.WriteHeader(http.StatusNotFound) - fmt.Fprintf(w, `{"error":"resolver for '%s:%s' network not found"}`, chain, networkid) + log.Printf(`{"error":"resolver for '%s:%s' network not found"}`, chain, networkid) return } else if err != nil { log.Printf("failed get info about latest gist from network '%s:%s': %v\n", chain, networkid, err) diff --git a/pkg/document/proof.go b/pkg/document/proof.go index c4511b1..e7e7215 100644 --- a/pkg/document/proof.go +++ b/pkg/document/proof.go @@ -25,6 +25,7 @@ type EthereumEip712SignatureProof2021 struct { } // EthereumEip712Signature2021Type is a proof type for EIP172 signature proofs +// nolint:stylecheck // we need to keep the name as it is const EthereumEip712SignatureProof2021Type verifiable.ProofType = "EthereumEip712Signature2021" func (p *EthereumEip712SignatureProof2021) ProofType() verifiable.ProofType { diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index e463619..2a99a6b 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -176,7 +176,8 @@ func (r *Resolver) Resolve( return services.IdentityState{}, errors.New("options GistRoot is required for root only did") } - stateInfo, gistInfo, err = r.resolveGistRootOnly(ctx, opts.GistRoot) + stateInfo = nil + gistInfo, err = r.resolveGistRootOnly(ctx, opts.GistRoot) } else { userID, err := core.IDFromDID(did) if err != nil { @@ -367,7 +368,7 @@ func (r *Resolver) verifyTypedData(authData AuthData) (bool, error) { return false, fmt.Errorf("decode signature: %w", err) } - // EIP-712 typed data marshalling + // EIP-712 typed data marshaling domainSeparator, err := authData.TypedData.HashStruct("EIP712Domain", authData.TypedData.Domain.Map()) if err != nil { return false, fmt.Errorf("eip712domain hash struct: %w", err) @@ -482,13 +483,13 @@ func (r *Resolver) resolveStateByGistRoot( func (r *Resolver) resolveGistRootOnly( ctx context.Context, gistRoot *big.Int, -) (*abi.IStateStateInfo, *abi.IStateGistRootInfo, error) { +) (*abi.IStateGistRootInfo, error) { gistInfo, err := r.state.GetGISTRootInfo(&bind.CallOpts{Context: ctx}, gistRoot) if err = notFoundErr(err); err != nil { - return nil, nil, err + return nil, err } - return nil, &gistInfo, nil + return &gistInfo, nil } func verifyContractState(id core.ID, state abi.IStateStateInfo) error { From e4af0958c598fe1df7c77526cee5cc4046471aa4 Mon Sep 17 00:00:00 2001 From: daveroga Date: Wed, 24 Jul 2024 09:47:42 +0200 Subject: [PATCH 13/18] add stateReplacedByState and gistRootReplacedByRoot in signature --- pkg/document/proof_test.go | 10 ++++++++ pkg/services/blockchain/eth/resolver.go | 14 ++++++++--- pkg/services/blockchain/eth/resolver_test.go | 26 ++++++++++++-------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/pkg/document/proof_test.go b/pkg/document/proof_test.go index a213862..90f19d1 100644 --- a/pkg/document/proof_test.go +++ b/pkg/document/proof_test.go @@ -30,9 +30,11 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { { "name": "timestamp", "type": "uint256" }, { "name": "state", "type": "uint256" }, { "name": "stateCreatedAtTimestamp", "type": "uint256" }, + { "name": "stateReplacedByState", "type": "uint256" }, { "name": "stateReplacedAtTimestamp", "type": "uint256" }, { "name": "gistRoot", "type": "uint256" }, { "name": "gistRootCreatedAtTimestamp", "type": "uint256" }, + { "name": "gistRootReplacedByRoot", "type": "uint256" }, { "name": "gistRootReplacedAtTimestamp", "type": "uint256" }, { "name": "identity", "type": "uint256" } ] @@ -49,9 +51,11 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { "timestamp": "0", "state": "444", "stateCreatedAtTimestamp": "0", + "stateReplacedByState": "0", "stateReplacedAtTimestamp": "0", "gistRoot": "555", "gistRootCreatedAtTimestamp": "0", + "gistRootReplacedByRoot": "0", "gistRootReplacedAtTimestamp": "0", "identity": "19090607534999372304474213543962416547920895595808567155882840509226423042" } @@ -69,9 +73,11 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { {Name: "timestamp", Type: "uint256"}, {Name: "state", Type: "uint256"}, {Name: "stateCreatedAtTimestamp", Type: "uint256"}, + {Name: "stateReplacedByState", Type: "uint256"}, {Name: "stateReplacedAtTimestamp", Type: "uint256"}, {Name: "gistRoot", Type: "uint256"}, {Name: "gistRootCreatedAtTimestamp", Type: "uint256"}, + {Name: "gistRootReplacedByRoot", Type: "uint256"}, {Name: "gistRootReplacedAtTimestamp", Type: "uint256"}, {Name: "identity", Type: "uint256"}, }, @@ -87,8 +93,10 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { walletAddress := "0x5b18eF56aA61eeAE0E3434e3c3d8AEB19b141fe7" state := "444" stateCreatedAtTimestamp := "0" + stateReplacedByState := "0" stateReplacedAtTimestamp := "0" gistRootCreatedAtTimestamp := "0" + gistRootReplacedByRoot := "0" gistRootReplacedAtTimestamp := "0" timestamp := "0" gistRoot := "555" @@ -115,9 +123,11 @@ func TestEthereumEip712SignatureProof2021_JSONUnmarshal(t *testing.T) { "timestamp": timestamp, "state": state, "stateCreatedAtTimestamp": stateCreatedAtTimestamp, + "stateReplacedByState": stateReplacedByState, "stateReplacedAtTimestamp": stateReplacedAtTimestamp, "gistRoot": gistRoot, "gistRootCreatedAtTimestamp": gistRootCreatedAtTimestamp, + "gistRootReplacedByRoot": gistRootReplacedByRoot, "gistRootReplacedAtTimestamp": gistRootReplacedAtTimestamp, "identity": identity, }, diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 2a99a6b..f5e925e 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -59,9 +59,11 @@ var apiTypes = apitypes.Types{ {Name: "timestamp", Type: "uint256"}, {Name: "state", Type: "uint256"}, {Name: "stateCreatedAtTimestamp", Type: "uint256"}, + {Name: "stateReplacedByState", Type: "uint256"}, {Name: "stateReplacedAtTimestamp", Type: "uint256"}, {Name: "gistRoot", Type: "uint256"}, {Name: "gistRootCreatedAtTimestamp", Type: "uint256"}, + {Name: "gistRootReplacedByRoot", Type: "uint256"}, {Name: "gistRootReplacedAtTimestamp", Type: "uint256"}, {Name: "identity", Type: "uint256"}, }, @@ -278,19 +280,23 @@ func (r *Resolver) TypedData(did w3c.DID, identityState services.IdentityState, } stateInfoState := "0" stateInfoCreatedAtTimestamp := "0" + stateInfoReplacedByState := "0" stateInfoReplacedAtTimestamp := "0" + gistInfoRoot := "0" + gistInfoCreatedAtTimestamp := "0" + gistInfoReplacedByRoot := "0" + gistInfoReplacedAtTimestamp := "0" if identityState.StateInfo != nil { stateInfoState = identityState.StateInfo.State.String() stateInfoCreatedAtTimestamp = identityState.StateInfo.CreatedAtTimestamp.String() + stateInfoReplacedByState = identityState.StateInfo.ReplacedByState.String() stateInfoReplacedAtTimestamp = identityState.StateInfo.ReplacedAtTimestamp.String() } - gistInfoRoot := "0" - gistInfoCreatedAtTimestamp := "0" - gistInfoReplacedAtTimestamp := "0" if identityState.GistInfo != nil { gistInfoRoot = identityState.GistInfo.Root.String() gistInfoCreatedAtTimestamp = identityState.GistInfo.CreatedAtTimestamp.String() + gistInfoReplacedByRoot = identityState.GistInfo.ReplacedByRoot.String() gistInfoReplacedAtTimestamp = identityState.GistInfo.ReplacedAtTimestamp.String() } @@ -309,9 +315,11 @@ func (r *Resolver) TypedData(did w3c.DID, identityState services.IdentityState, "timestamp": timestamp, "state": stateInfoState, "stateCreatedAtTimestamp": stateInfoCreatedAtTimestamp, + "stateReplacedByState": stateInfoReplacedByState, "stateReplacedAtTimestamp": stateInfoReplacedAtTimestamp, "gistRoot": gistInfoRoot, "gistRootCreatedAtTimestamp": gistInfoCreatedAtTimestamp, + "gistRootReplacedByRoot": gistInfoReplacedByRoot, "gistRootReplacedAtTimestamp": gistInfoReplacedAtTimestamp, "identity": identity, }, diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index 153b15a..c2b98c1 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -231,9 +231,9 @@ func TestResolveSignature_Success(t *testing.T) { } userID, _ := core.IDFromDID(*userDID) c.EXPECT().GetGISTProofByRoot(gomock.Any(), userID.BigInt(), big.NewInt(1)).Return(proof, nil) - gistInfo := abi.IStateGistRootInfo{Root: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} + gistInfo := abi.IStateGistRootInfo{Root: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetGISTRootInfo(gomock.Any(), big.NewInt(4)).Return(gistInfo, nil) - stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(444), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} + stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(444), CreatedAtTimestamp: big.NewInt(0), ReplacedByState: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoByIdAndState(gomock.Any(), gomock.Any(), big.NewInt(5)).Return(stateInfo, nil) }, timeStamp: func() string { @@ -244,14 +244,16 @@ func TestResolveSignature_Success(t *testing.T) { ID: *userDID, State: big.NewInt(444), CreatedAtTimestamp: big.NewInt(0), + ReplacedByState: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: &services.GistInfo{ Root: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), + ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0xe63151912749d0cae7fea6a13dda6d54061626cc03a79dac46b6a11b3259c6c335d8266f09eaf070a31c8a23765fb01e3c8bf927f5ab25346f743ae309eabc801c", + Signature: "0xedbe6cd15241ee8cd6a76446fbdf44e90df28c42eaff606ea6cd55d97158c036187aad5556753bd7a306cd71bdaddfac7af7f4127b66e4159d3d6d69548ba4de1c", }, }, { @@ -263,7 +265,7 @@ func TestResolveSignature_Success(t *testing.T) { userDID: userDID, contractMock: func(c *cm.MockStateContract) { userID, _ := core.IDFromDID(*userDID) - res := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} + res := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedByState: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoByIdAndState(gomock.Any(), gomock.Any(), big.NewInt(1)).Return(res, nil) }, timeStamp: func() string { @@ -274,10 +276,11 @@ func TestResolveSignature_Success(t *testing.T) { ID: *userDID, State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), + ReplacedByState: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: nil, - Signature: "0x3dce5819f16b5225bbe9ec3ce144b45654119f4cfdff2f9e8f5d33a0fc3790de570dfacdc304ee217b43952c9393425fc45f5abc9e9f7e5b63196479319eb62c1b", + Signature: "0x3fe7236be270e37125e265ced2b5be614909015d9636c7bca14e9adca38a9b5e789cedaa32edec24b9c1226df1ed4d86dafa8ab1587fb6d29b07e040dfb1b2861c", }, }, { @@ -290,9 +293,9 @@ func TestResolveSignature_Success(t *testing.T) { userID, _ := core.IDFromDID(*userDID) latestGist := big.NewInt(100) c.EXPECT().GetGISTRoot(gomock.Any()).Return(latestGist, nil) - latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} + latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetGISTRootInfo(gomock.Any(), latestGist).Return(latestGistInfo, nil) - stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} + stateInfo := abi.IStateStateInfo{Id: userID.BigInt(), State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), ReplacedByState: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetStateInfoById(gomock.Any(), userID.BigInt()).Return(stateInfo, nil) }, timeStamp: func() string { @@ -303,14 +306,16 @@ func TestResolveSignature_Success(t *testing.T) { ID: *userDID, State: big.NewInt(555), CreatedAtTimestamp: big.NewInt(0), + ReplacedByState: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: &services.GistInfo{ Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), + ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0x866206f5be01973be72631fd9931d8ccc7d6e8612f799dc39ff495d1e3a975af7c81c0e4fc13e50f4177fbc637e81ca546ee2906eccf1dfa96687fff05bd49831c", + Signature: "0x8a39cf242b4474f62ad3579c31ae42e5981c0237fe6232513528f2731defc3db553535f23895a7d444d31a7643924071ce34f8a3dd308bfcbf1d4a90eb6ee5571c", }, }, { @@ -322,7 +327,7 @@ func TestResolveSignature_Success(t *testing.T) { userDID: userEmptyDID, contractMock: func(c *cm.MockStateContract) { latestGist := big.NewInt(400) - latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} + latestGistInfo := abi.IStateGistRootInfo{Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0)} c.EXPECT().GetGISTRootInfo(gomock.Any(), latestGist).Return(latestGistInfo, nil) }, timeStamp: func() string { @@ -333,9 +338,10 @@ func TestResolveSignature_Success(t *testing.T) { GistInfo: &services.GistInfo{ Root: big.NewInt(400), CreatedAtTimestamp: big.NewInt(0), + ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0xec3a8bd564247bed3c16f719d499e02d4914a8fa10704a8f3dcae75ca393b3ae47c3f147355f5476cb495b8e0463fd128da2795c02bd9420f8071d93652d13b81b", + Signature: "0xb38e057dddbb4636ecf7a8f9d1eefc352ee0c8e395857462859509d9e40c68bf731e285117f571f5805bcbc6fb13a16fadd83d963d8a3918a793cf8877a363481b", }, }, } From 413073c095b438b80c9265d80cd918a7b56c5c50 Mon Sep 17 00:00:00 2001 From: daveroga Date: Wed, 24 Jul 2024 18:44:09 +0200 Subject: [PATCH 14/18] split signed messages in GlobalState and IdentityState --- pkg/document/did.go | 1 + pkg/services/blockchain/eth/resolver.go | 125 ++++++++++++------- pkg/services/blockchain/eth/resolver_test.go | 15 ++- pkg/services/did.go | 8 +- pkg/services/registry.go | 9 +- 5 files changed, 104 insertions(+), 54 deletions(-) diff --git a/pkg/document/did.go b/pkg/document/did.go index 6338ff2..9ec3d9d 100644 --- a/pkg/document/did.go +++ b/pkg/document/did.go @@ -84,6 +84,7 @@ type DidResolutionMetadata struct { Message string `json:"message,omitempty"` ContentType string `json:"contentType,omitempty"` Retrieved time.Time `json:"retrieved,omitempty"` + Type string `json:"type,omitempty"` Proof DidResolutionProofs `json:"proof,omitempty"` } diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index f5e925e..7ed4d46 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -53,19 +53,15 @@ var ( stateNotFoundException = "execution reverted: State does not exist" ) -var apiTypes = apitypes.Types{ +var IdentityStateApiTypes = apitypes.Types{ "IdentityState": []apitypes.Type{ {Name: "from", Type: "address"}, {Name: "timestamp", Type: "uint256"}, - {Name: "state", Type: "uint256"}, - {Name: "stateCreatedAtTimestamp", Type: "uint256"}, - {Name: "stateReplacedByState", Type: "uint256"}, - {Name: "stateReplacedAtTimestamp", Type: "uint256"}, - {Name: "gistRoot", Type: "uint256"}, - {Name: "gistRootCreatedAtTimestamp", Type: "uint256"}, - {Name: "gistRootReplacedByRoot", Type: "uint256"}, - {Name: "gistRootReplacedAtTimestamp", Type: "uint256"}, {Name: "identity", Type: "uint256"}, + {Name: "state", Type: "uint256"}, + {Name: "replacedByState", Type: "uint256"}, + {Name: "createdAtTimestamp", Type: "uint256"}, + {Name: "replacedAtTimestamp", Type: "uint256"}, }, "EIP712Domain": []apitypes.Type{ {Name: "name", Type: "string"}, @@ -75,7 +71,22 @@ var apiTypes = apitypes.Types{ }, } -var primaryType = "IdentityState" +var GlobalStateApiTypes = apitypes.Types{ + "GlobalState": []apitypes.Type{ + {Name: "from", Type: "address"}, + {Name: "timestamp", Type: "uint256"}, + {Name: "root", Type: "uint256"}, + {Name: "replacedByRoot", Type: "uint256"}, + {Name: "createdAtTimestamp", Type: "uint256"}, + {Name: "replacedAtTimestamp", Type: "uint256"}, + }, + "EIP712Domain": []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, +} var TimeStamp = TimeStampFn @@ -226,7 +237,11 @@ func (r *Resolver) Resolve( signature := "" if r.walletKey != "" && opts.Signature != "" { - signature, err = r.signTypedData(did, identityState) + primaryType := services.IDENTITY_STATE_TYPE + if stateInfo == nil { + primaryType = services.GLOBAL_STATE_TYPE + } + signature, err = r.signTypedData(primaryType, did, identityState) if err != nil { return services.IdentityState{}, err } @@ -237,7 +252,8 @@ func (r *Resolver) Resolve( return identityState, err } -func (r *Resolver) VerifyIdentityState( +func (r *Resolver) VerifyState( + primaryType services.PrimaryType, identityState services.IdentityState, did w3c.DID, ) (bool, error) { @@ -254,7 +270,7 @@ func (r *Resolver) VerifyIdentityState( walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) - typedData, err := r.TypedData(did, identityState, walletAddress.String()) + typedData, err := r.TypedData(primaryType, did, identityState, walletAddress.String()) if err != nil { return false, err } @@ -268,7 +284,7 @@ func TimeStampFn() string { return timestamp } -func (r *Resolver) TypedData(did w3c.DID, identityState services.IdentityState, walletAddress string) (apitypes.TypedData, error) { +func (r *Resolver) TypedData(primaryType services.PrimaryType, did w3c.DID, identityState services.IdentityState, walletAddress string) (apitypes.TypedData, error) { identity := "0" if did.IDStrings[2] != "000000000000000000000000000000000000000000" { userID, err := core.IDFromDID(did) @@ -278,57 +294,74 @@ func (r *Resolver) TypedData(did w3c.DID, identityState services.IdentityState, } identity = userID.BigInt().String() } - stateInfoState := "0" - stateInfoCreatedAtTimestamp := "0" - stateInfoReplacedByState := "0" - stateInfoReplacedAtTimestamp := "0" - gistInfoRoot := "0" - gistInfoCreatedAtTimestamp := "0" - gistInfoReplacedByRoot := "0" - gistInfoReplacedAtTimestamp := "0" + + root := "0" + state := "0" + createdAtTimestamp := "0" + replacedByRoot := "0" + replacedByState := "0" + replacedAtTimestamp := "0" if identityState.StateInfo != nil { - stateInfoState = identityState.StateInfo.State.String() - stateInfoCreatedAtTimestamp = identityState.StateInfo.CreatedAtTimestamp.String() - stateInfoReplacedByState = identityState.StateInfo.ReplacedByState.String() - stateInfoReplacedAtTimestamp = identityState.StateInfo.ReplacedAtTimestamp.String() + state = identityState.StateInfo.State.String() + replacedByState = identityState.StateInfo.ReplacedByState.String() + createdAtTimestamp = identityState.StateInfo.CreatedAtTimestamp.String() + replacedAtTimestamp = identityState.StateInfo.ReplacedAtTimestamp.String() } if identityState.GistInfo != nil { - gistInfoRoot = identityState.GistInfo.Root.String() - gistInfoCreatedAtTimestamp = identityState.GistInfo.CreatedAtTimestamp.String() - gistInfoReplacedByRoot = identityState.GistInfo.ReplacedByRoot.String() - gistInfoReplacedAtTimestamp = identityState.GistInfo.ReplacedAtTimestamp.String() + root = identityState.GistInfo.Root.String() + replacedByRoot = identityState.GistInfo.ReplacedByRoot.String() + createdAtTimestamp = identityState.GistInfo.CreatedAtTimestamp.String() + replacedAtTimestamp = identityState.GistInfo.ReplacedAtTimestamp.String() } + apiTypes := apitypes.Types{} + message := apitypes.TypedDataMessage{} + primaryTypeString := "" timestamp := TimeStamp() + + switch primaryType { + case services.IDENTITY_STATE_TYPE: + primaryTypeString = "IdentityState" + apiTypes = IdentityStateApiTypes + message = apitypes.TypedDataMessage{ + "from": walletAddress, + "timestamp": timestamp, + "identity": identity, + "state": state, + "replacedByState": replacedByState, + "createdAtTimestamp": createdAtTimestamp, + "replacedAtTimestamp": replacedAtTimestamp, + } + case services.GLOBAL_STATE_TYPE: + primaryTypeString = "GlobalState" + apiTypes = GlobalStateApiTypes + message = apitypes.TypedDataMessage{ + "from": walletAddress, + "timestamp": timestamp, + "root": root, + "replacedByRoot": replacedByRoot, + "createdAtTimestamp": createdAtTimestamp, + "replacedAtTimestamp": replacedAtTimestamp, + } + } + typedData := apitypes.TypedData{ Types: apiTypes, - PrimaryType: primaryType, + PrimaryType: primaryTypeString, Domain: apitypes.TypedDataDomain{ Name: "StateInfo", Version: "1", ChainId: math.NewHexOrDecimal256(int64(0)), VerifyingContract: "0x0000000000000000000000000000000000000000", }, - Message: apitypes.TypedDataMessage{ - "from": walletAddress, - "timestamp": timestamp, - "state": stateInfoState, - "stateCreatedAtTimestamp": stateInfoCreatedAtTimestamp, - "stateReplacedByState": stateInfoReplacedByState, - "stateReplacedAtTimestamp": stateInfoReplacedAtTimestamp, - "gistRoot": gistInfoRoot, - "gistRootCreatedAtTimestamp": gistInfoCreatedAtTimestamp, - "gistRootReplacedByRoot": gistInfoReplacedByRoot, - "gistRootReplacedAtTimestamp": gistInfoReplacedAtTimestamp, - "identity": identity, - }, + Message: message, } return typedData, nil } -func (r *Resolver) signTypedData(did w3c.DID, identityState services.IdentityState) (string, error) { +func (r *Resolver) signTypedData(primaryType services.PrimaryType, did w3c.DID, identityState services.IdentityState) (string, error) { privateKey, err := crypto.HexToECDSA(r.walletKey) if err != nil { return "", err @@ -342,7 +375,7 @@ func (r *Resolver) signTypedData(did w3c.DID, identityState services.IdentitySta walletAddress := crypto.PubkeyToAddress(*publicKeyECDSA) - typedData, err := r.TypedData(did, identityState, walletAddress.String()) + typedData, err := r.TypedData(primaryType, did, identityState, walletAddress.String()) if err != nil { return "", errors.New("error getting typed data for signing") } diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index c2b98c1..83f500b 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -253,7 +253,7 @@ func TestResolveSignature_Success(t *testing.T) { ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0xedbe6cd15241ee8cd6a76446fbdf44e90df28c42eaff606ea6cd55d97158c036187aad5556753bd7a306cd71bdaddfac7af7f4127b66e4159d3d6d69548ba4de1c", + Signature: "0x6276946bac246584ed6eaa2d5e43be5147e67cc7aa3b969c82bb9b1670e8de8b7f7410286f25d6bee4330b4bc260286cf8505358ffa29c8e677e4f05d78acf131c", }, }, { @@ -280,7 +280,7 @@ func TestResolveSignature_Success(t *testing.T) { ReplacedAtTimestamp: big.NewInt(0), }, GistInfo: nil, - Signature: "0x3fe7236be270e37125e265ced2b5be614909015d9636c7bca14e9adca38a9b5e789cedaa32edec24b9c1226df1ed4d86dafa8ab1587fb6d29b07e040dfb1b2861c", + Signature: "0xdd07cd99ee8aa853c3e942aa5d57bfb844cae3db35fe29e8fc635ff4b2f5377d4b3c65f270474e6c5931b3d77f536233bc56d63172da8dba188f1f6fa51a10cb1c", }, }, { @@ -315,7 +315,7 @@ func TestResolveSignature_Success(t *testing.T) { ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0x8a39cf242b4474f62ad3579c31ae42e5981c0237fe6232513528f2731defc3db553535f23895a7d444d31a7643924071ce34f8a3dd308bfcbf1d4a90eb6ee5571c", + Signature: "0xdd07cd99ee8aa853c3e942aa5d57bfb844cae3db35fe29e8fc635ff4b2f5377d4b3c65f270474e6c5931b3d77f536233bc56d63172da8dba188f1f6fa51a10cb1c", }, }, { @@ -341,7 +341,7 @@ func TestResolveSignature_Success(t *testing.T) { ReplacedByRoot: big.NewInt(0), ReplacedAtTimestamp: big.NewInt(0), }, - Signature: "0xb38e057dddbb4636ecf7a8f9d1eefc352ee0c8e395857462859509d9e40c68bf731e285117f571f5805bcbc6fb13a16fadd83d963d8a3918a793cf8877a363481b", + Signature: "0xe64e080d08b948e5303b49288f1ff599df5b21fd20d7a944026a17e69f860e21662538ec1f8cba2f4a76e7c25d0f5cf506dc16bbc3148158ed81dd899528c69f1c", }, }, } @@ -363,7 +363,12 @@ func TestResolveSignature_Success(t *testing.T) { require.NoError(t, err) require.Equal(t, tt.expectedIdentityState, identityState) - ok, _ := resolver.VerifyIdentityState(identityState, *tt.userDID) + primaryType := services.IDENTITY_STATE_TYPE + if tt.expectedIdentityState.StateInfo == nil { + primaryType = services.GLOBAL_STATE_TYPE + } + + ok, _ := resolver.VerifyState(primaryType, identityState, *tt.userDID) require.Equal(t, true, ok) ctrl.Finish() }) diff --git a/pkg/services/did.go b/pkg/services/did.go index ee2ebdb..ea75a78 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -142,7 +142,11 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op walletAddress, err := resolver.WalletAddress() if err == nil && opts.Signature != "" { - eip712TypedData, err := resolver.TypedData(*userDID, identityState, walletAddress) + primaryType := IDENTITY_STATE_TYPE + if userDID.IDStrings[2] == "000000000000000000000000000000000000000000" { + primaryType = GLOBAL_STATE_TYPE + } + eip712TypedData, err := resolver.TypedData(primaryType, *userDID, identityState, walletAddress) if err != nil { return nil, fmt.Errorf("invalid typed data: %v", err) } @@ -151,7 +155,7 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op Type: document.EthereumEip712SignatureProof2021Type, ProofPursopose: "assertionMethod", ProofValue: identityState.Signature, - VerificationMethod: fmt.Sprintf("did:pkh:eip155:%s:%s#blockchainAccountId", strings.Split(chainIDStateAddress, ":")[0], walletAddress), + VerificationMethod: fmt.Sprintf("did:pkh:eip155:0:%s#blockchainAccountId", walletAddress), Eip712: eip712TypedData, Created: time.Now(), } diff --git a/pkg/services/registry.go b/pkg/services/registry.go index c7810b9..77c5fff 100644 --- a/pkg/services/registry.go +++ b/pkg/services/registry.go @@ -19,6 +19,13 @@ var ( ErrNotFound = errors.New("not found") ) +type PrimaryType int32 + +const ( + IDENTITY_STATE_TYPE PrimaryType = 0 + GLOBAL_STATE_TYPE PrimaryType = 1 +) + type IdentityState struct { StateInfo *StateInfo GistInfo *GistInfo @@ -98,7 +105,7 @@ type Resolver interface { ResolveGist(ctx context.Context, opts *ResolverOpts) (*GistInfo, error) BlockchainID() string WalletAddress() (string, error) - TypedData(did w3c.DID, identityState IdentityState, walletAddress string) (apitypes.TypedData, error) + TypedData(primaryType PrimaryType, did w3c.DID, identityState IdentityState, walletAddress string) (apitypes.TypedData, error) } type ResolverRegistry map[string]Resolver From 30b97c4ef6509e06a443ed1a219929809b8ab947 Mon Sep 17 00:00:00 2001 From: daveroga Date: Wed, 24 Jul 2024 18:52:31 +0200 Subject: [PATCH 15/18] fix lint errors --- pkg/services/blockchain/eth/resolver.go | 16 ++++++++-------- pkg/services/blockchain/eth/resolver_test.go | 4 ++-- pkg/services/did.go | 4 ++-- pkg/services/registry.go | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/services/blockchain/eth/resolver.go b/pkg/services/blockchain/eth/resolver.go index 7ed4d46..2f2b9ab 100644 --- a/pkg/services/blockchain/eth/resolver.go +++ b/pkg/services/blockchain/eth/resolver.go @@ -53,7 +53,7 @@ var ( stateNotFoundException = "execution reverted: State does not exist" ) -var IdentityStateApiTypes = apitypes.Types{ +var IdentityStateAPITypes = apitypes.Types{ "IdentityState": []apitypes.Type{ {Name: "from", Type: "address"}, {Name: "timestamp", Type: "uint256"}, @@ -71,7 +71,7 @@ var IdentityStateApiTypes = apitypes.Types{ }, } -var GlobalStateApiTypes = apitypes.Types{ +var GlobalStateAPITypes = apitypes.Types{ "GlobalState": []apitypes.Type{ {Name: "from", Type: "address"}, {Name: "timestamp", Type: "uint256"}, @@ -237,9 +237,9 @@ func (r *Resolver) Resolve( signature := "" if r.walletKey != "" && opts.Signature != "" { - primaryType := services.IDENTITY_STATE_TYPE + primaryType := services.IdentityStateType if stateInfo == nil { - primaryType = services.GLOBAL_STATE_TYPE + primaryType = services.GlobalStateType } signature, err = r.signTypedData(primaryType, did, identityState) if err != nil { @@ -321,9 +321,9 @@ func (r *Resolver) TypedData(primaryType services.PrimaryType, did w3c.DID, iden timestamp := TimeStamp() switch primaryType { - case services.IDENTITY_STATE_TYPE: + case services.IdentityStateType: primaryTypeString = "IdentityState" - apiTypes = IdentityStateApiTypes + apiTypes = IdentityStateAPITypes message = apitypes.TypedDataMessage{ "from": walletAddress, "timestamp": timestamp, @@ -333,9 +333,9 @@ func (r *Resolver) TypedData(primaryType services.PrimaryType, did w3c.DID, iden "createdAtTimestamp": createdAtTimestamp, "replacedAtTimestamp": replacedAtTimestamp, } - case services.GLOBAL_STATE_TYPE: + case services.GlobalStateType: primaryTypeString = "GlobalState" - apiTypes = GlobalStateApiTypes + apiTypes = GlobalStateAPITypes message = apitypes.TypedDataMessage{ "from": walletAddress, "timestamp": timestamp, diff --git a/pkg/services/blockchain/eth/resolver_test.go b/pkg/services/blockchain/eth/resolver_test.go index 83f500b..3672139 100644 --- a/pkg/services/blockchain/eth/resolver_test.go +++ b/pkg/services/blockchain/eth/resolver_test.go @@ -363,9 +363,9 @@ func TestResolveSignature_Success(t *testing.T) { require.NoError(t, err) require.Equal(t, tt.expectedIdentityState, identityState) - primaryType := services.IDENTITY_STATE_TYPE + primaryType := services.IdentityStateType if tt.expectedIdentityState.StateInfo == nil { - primaryType = services.GLOBAL_STATE_TYPE + primaryType = services.GlobalStateType } ok, _ := resolver.VerifyState(primaryType, identityState, *tt.userDID) diff --git a/pkg/services/did.go b/pkg/services/did.go index ea75a78..d37e76c 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -142,9 +142,9 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op walletAddress, err := resolver.WalletAddress() if err == nil && opts.Signature != "" { - primaryType := IDENTITY_STATE_TYPE + primaryType := IdentityStateType if userDID.IDStrings[2] == "000000000000000000000000000000000000000000" { - primaryType = GLOBAL_STATE_TYPE + primaryType = GlobalStateType } eip712TypedData, err := resolver.TypedData(primaryType, *userDID, identityState, walletAddress) if err != nil { diff --git a/pkg/services/registry.go b/pkg/services/registry.go index 77c5fff..5e858a2 100644 --- a/pkg/services/registry.go +++ b/pkg/services/registry.go @@ -22,8 +22,8 @@ var ( type PrimaryType int32 const ( - IDENTITY_STATE_TYPE PrimaryType = 0 - GLOBAL_STATE_TYPE PrimaryType = 1 + IdentityStateType PrimaryType = 0 + GlobalStateType PrimaryType = 1 ) type IdentityState struct { From 032a6973f084ea6f3161dbcbe53a43dd84a4e8fa Mon Sep 17 00:00:00 2001 From: daveroga Date: Thu, 25 Jul 2024 16:37:32 +0200 Subject: [PATCH 16/18] add context for Iden3ResolutionMetadata --- pkg/document/did.go | 16 ++++++++++++---- pkg/services/did.go | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/pkg/document/did.go b/pkg/document/did.go index 9ec3d9d..f49788b 100644 --- a/pkg/document/did.go +++ b/pkg/document/did.go @@ -15,14 +15,17 @@ const ( ErrUnknownNetwork ErrorCode = "unknownNetwork" StateType = "Iden3StateInfo2023" + Iden3ResolutionMetadataType = "Iden3ResolutionMetadata" EcdsaSecp256k1RecoveryMethod2020Type = "EcdsaSecp256k1RecoveryMethod2020" ) const ( - defaultContext = "https://w3id.org/did-resolution/v1" - defaultDidDocContext = "https://www.w3.org/ns/did/v1" - iden3Context = "https://schema.iden3.io/core/jsonld/auth.jsonld" - defaultContentType = "application/did+ld+json" + defaultContext = "https://w3id.org/did-resolution/v1" + defaultDidDocContext = "https://www.w3.org/ns/did/v1" + iden3Context = "https://schema.iden3.io/core/jsonld/auth.jsonld" + defaultContentType = "application/did+ld+json" + iden3ResolutionContext = "https://schema.iden3.io/core/jsonld/resolution.jsonld" + eip712sigContext = "https://w3id.org/security/suites/eip712sig-2021/v1" ) // DidResolution representation of did resolution. @@ -51,6 +54,10 @@ func NewDidResolution() *DidResolution { } } +func DidResolutionMetadataSigContext() []string { + return []string{iden3ResolutionContext, eip712sigContext} +} + func NewDidMethodNotSupportedResolution(msg string) *DidResolution { return NewDidErrorResolution(ErrMethodNotSupported, msg) } @@ -80,6 +87,7 @@ func NewDidErrorResolution(errCode ErrorCode, errMsg string) *DidResolution { // DidResolutionMetadata representation of resolution metadata. type DidResolutionMetadata struct { + Context interface{} `json:"@context,omitempty"` Error ErrorCode `json:"error,omitempty"` Message string `json:"message,omitempty"` ContentType string `json:"contentType,omitempty"` diff --git a/pkg/services/did.go b/pkg/services/did.go index d37e76c..51988a8 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -160,6 +160,8 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op Created: time.Now(), } + didResolution.DidResolutionMetadata.Context = document.DidResolutionMetadataSigContext() + didResolution.DidResolutionMetadata.Type = document.Iden3ResolutionMetadataType didResolution.DidResolutionMetadata.Proof = append(didResolution.DidResolutionMetadata.Proof, eip712Proof) } From ad8adcac156b4b386ac5e174d5652c2aa06c4941 Mon Sep 17 00:00:00 2001 From: daveroga Date: Thu, 25 Jul 2024 16:55:07 +0200 Subject: [PATCH 17/18] add type always in didResolutionMetadata --- pkg/document/did.go | 2 ++ pkg/services/did.go | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/document/did.go b/pkg/document/did.go index f49788b..c04571d 100644 --- a/pkg/document/did.go +++ b/pkg/document/did.go @@ -47,6 +47,8 @@ func NewDidResolution() *DidResolution { VerificationMethod: []verifiable.CommonVerificationMethod{}, }, DidResolutionMetadata: &DidResolutionMetadata{ + Context: []string{iden3ResolutionContext}, + Type: Iden3ResolutionMetadataType, ContentType: defaultContentType, Retrieved: time.Now(), }, diff --git a/pkg/services/did.go b/pkg/services/did.go index 51988a8..b72e651 100644 --- a/pkg/services/did.go +++ b/pkg/services/did.go @@ -161,7 +161,6 @@ func (d *DidDocumentServices) GetDidDocument(ctx context.Context, did string, op } didResolution.DidResolutionMetadata.Context = document.DidResolutionMetadataSigContext() - didResolution.DidResolutionMetadata.Type = document.Iden3ResolutionMetadataType didResolution.DidResolutionMetadata.Proof = append(didResolution.DidResolutionMetadata.Proof, eip712Proof) } From a60f2d46b70e261d1a5472db24070efcf0c4c63a Mon Sep 17 00:00:00 2001 From: daveroga Date: Thu, 25 Jul 2024 17:10:47 +0200 Subject: [PATCH 18/18] add comment about walletKey parameter in reoslvers.settings.yaml --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4bb0514..7197bdd 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ Driver for the polygonid DID method. amoy: contractAddress: "0x1a4cC30f2aA0377b0c3bc9848766D90cb4404124" networkURL: "https://polygon-amoy..." + walletKey: "" ``` + `walletKey` is only needed for the resolver if it's a trusted resolver that includes signature of EIP712 message when requested in the resolution with `signature=EthereumEip712Signature2021`. 2. Build docker container: ```bash docker build -t driver-did-polygonid:local . @@ -26,6 +28,7 @@ Driver for the polygonid DID method. amoy: contractAddress: "0x1a4cC30f2aA0377b0c3bc9848766D90cb4404124" networkURL: "" + walletKey: "" ``` 2. Build docker container: ```bash