diff --git a/auth.go b/auth.go index 46a0cba..35e4ac4 100644 --- a/auth.go +++ b/auth.go @@ -9,6 +9,9 @@ import ( "log" "math/big" "net/http" + "net/url" + "strconv" + "strings" "time" "github.com/ethereum/go-ethereum/common" @@ -20,6 +23,7 @@ import ( "github.com/iden3/go-iden3-auth/v2/proofs" "github.com/iden3/go-iden3-auth/v2/pubsignals" "github.com/iden3/go-iden3-auth/v2/state" + core "github.com/iden3/go-iden3-core/v2" "github.com/iden3/go-iden3-core/v2/w3c" "github.com/iden3/go-jwz/v2" schemaloaders "github.com/iden3/go-schema-processor/v2/loaders" @@ -153,6 +157,58 @@ func newOpts() verifierOpts { } } +// ParseConnectionString parses the connection string and returns a map of state resolvers. +// The connection string format is as follows: +// +// chainID1=rpcURL1|contractAddress1;chainID2=rpcURL2|contractAddress2;... +// +// Each chainID is an integer representing the blockchain ID. +// Each rpcURL is the URL of the RPC endpoint for the blockchain. +// Each contractAddress is the address of the contract on the blockchain. +// The function returns an error if the connection string is in an invalid format or if the contract address is invalid. +// If the length of the result is 0, it means no connection info was found and an error is returned. +func ParseConnectionString(str string) (map[string]pubsignals.StateResolver, error) { + str = strings.TrimSpace(str) + result := make(map[string]pubsignals.StateResolver) + connectionInfo := strings.Split(str, ";") + for _, chain := range connectionInfo { + parts := strings.Split(chain, "=") + if len(parts) != 2 { + return nil, errors.Errorf("invalid format: '%s'", chain) + } + chainIDstr := parts[0] + rpcToContractAddress := strings.Split(parts[1], "|") + if len(rpcToContractAddress) != 2 { + return nil, errors.Errorf("invalid format: '%s'", parts[1]) + } + + _, err := url.ParseRequestURI(rpcToContractAddress[0]) + if err != nil { + return nil, errors.Errorf("invalid rpc url: '%s'", rpcToContractAddress[0]) + } + if common.HexToAddress(rpcToContractAddress[1]).Hex() == (common.Address{}).Hex() { + return nil, errors.Errorf("invalid contract address: '%s'", rpcToContractAddress[1]) + } + + chainID, err := strconv.Atoi(chainIDstr) + if err != nil { + return nil, errors.Errorf("invalid chain id: '%s'", chainIDstr) + } + //nolint:gosec // integer overflow is not possible here + blockchain, network, err := core.NetworkByChainID(core.ChainID(chainID)) + if err != nil { + return nil, errors.Errorf("invalid chain id: '%s'", chainIDstr) + } + + c := state.NewETHResolver(rpcToContractAddress[0], rpcToContractAddress[1]) + result[fmt.Sprintf("%s:%s", blockchain, network)] = c + } + if len(result) == 0 { + return nil, errors.New("no connection info found") + } + return result, nil +} + // NewVerifier returns setup instance of auth library func NewVerifier( keyLoader loaders.VerificationKeyLoader, @@ -239,7 +295,7 @@ func (v *Verifier) SetupAuthV2ZKPPacker() error { // SetupJWSPacker sets the JWS packer for the VerifierBuilder. func (v *Verifier) SetupJWSPacker(didResolver packers.DIDResolverHandlerFunc) error { - signerFnStub := packers.SignerResolverHandlerFunc(func(kid string) (crypto.Signer, error) { + signerFnStub := packers.SignerResolverHandlerFunc(func(_ string) (crypto.Signer, error) { return nil, nil }) jwsPacker := packers.NewJWSPacker(didResolver, signerFnStub) diff --git a/auth_test.go b/auth_test.go index 7699c14..bda75df 100644 --- a/auth_test.go +++ b/auth_test.go @@ -1225,3 +1225,75 @@ func TestFullVerifyLinkedProofsVerification(t *testing.T) { require.NotNil(t, returnMsg) schemaLoader.assert(t) } + +func TestParseConnectionString(t *testing.T) { + tests := []struct { + name string + input string + want map[string]pubsignals.StateResolver + wantErr bool + errMsg string + }{ + { + name: "Valid input", + input: "1=http://localhost:8545|0x1234567890abcdef1234567890abcdef12345678", + want: map[string]pubsignals.StateResolver{"eth:main": state.NewETHResolver("http://localhost:8545", "0x1234567890abcdef1234567890abcdef12345678")}, + wantErr: false, + }, + { + name: "Invalid format - missing =", + input: "1http://localhost:8545|0x1234567890abcdef1234567890abcdef12345678", + wantErr: true, + errMsg: "invalid format: '1http://localhost:8545|0x1234567890abcdef1234567890abcdef12345678'", + }, + { + name: "Invalid format - missing |", + input: "1=http://localhost:85450x1234567890abcdef1234567890abcdef12345678", + wantErr: true, + errMsg: "invalid format: 'http://localhost:85450x1234567890abcdef1234567890abcdef12345678'", + }, + { + name: "Invalid RPC URL", + input: "1=invalid_url|0x1234567890abcdef1234567890abcdef12345678", + wantErr: true, + errMsg: "invalid rpc url: 'invalid_url'", + }, + { + name: "Invalid contract address", + input: "1=http://localhost:8545|invalid_address", + wantErr: true, + errMsg: "invalid contract address: 'invalid_address'", + }, + { + name: "Invalid chain ID", + input: "invalid_chain_id=http://localhost:8545|0x1234567890abcdef1234567890abcdef12345678", + wantErr: true, + errMsg: "invalid chain id: 'invalid_chain_id'", + }, + { + name: "Unknown chain ID", + input: "9999=http://localhost:8545|0x1234567890abcdef1234567890abcdef12345678", + wantErr: true, + errMsg: "invalid chain id: '9999'", + }, + { + name: "Empty input", + input: "", + wantErr: true, + errMsg: "invalid format: ''", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseConnectionString(tt.input) + if tt.wantErr { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.errMsg) + } else { + require.NoError(t, err) + assert.Equal(t, tt.want, got) + } + }) + } +} diff --git a/go.mod b/go.mod index e831e69..a2b7e0a 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( github.com/google/uuid v1.6.0 github.com/iden3/contracts-abi/state/go/abi v1.0.1 github.com/iden3/go-circuits/v2 v2.3.0 - github.com/iden3/go-iden3-core/v2 v2.2.0 - github.com/iden3/go-iden3-crypto v0.0.16 + github.com/iden3/go-iden3-core/v2 v2.3.1 + github.com/iden3/go-iden3-crypto v0.0.17 github.com/iden3/go-jwz/v2 v2.1.1 github.com/iden3/go-rapidsnark/types v0.0.3 github.com/iden3/go-rapidsnark/verifier v0.0.5 @@ -19,7 +19,7 @@ require ( github.com/ipfs/go-ipfs-api v0.7.0 github.com/piprate/json-gold v0.5.1-0.20230111113000-6ddbe6e6f19f github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 ) require ( diff --git a/go.sum b/go.sum index 6b2b5fe..ebdec82 100644 --- a/go.sum +++ b/go.sum @@ -110,10 +110,10 @@ github.com/iden3/contracts-abi/state/go/abi v1.0.1 h1:FsaLJSy3NSyJl5k1yfDxc5DhUH github.com/iden3/contracts-abi/state/go/abi v1.0.1/go.mod h1:TxgIrXCvxms3sbOdsy8kTvffUCIpEEifNy0fSXdkU4w= github.com/iden3/go-circuits/v2 v2.3.0 h1:xzDVuq4JkTgtz+AjatquuPgGVbOxRpcWMhUOcWEZJN4= github.com/iden3/go-circuits/v2 v2.3.0/go.mod h1:APhXQaRQr4txd+u0Y7liBjN/Wnox0d31wR40LkXywAE= -github.com/iden3/go-iden3-core/v2 v2.2.0 h1:PcMSxJRLAoJausj1gKstzgt25HS18K+IHLaSPeI9p8Q= -github.com/iden3/go-iden3-core/v2 v2.2.0/go.mod h1:L9PxhWPvoS9qTb3inEkZBm1RpjHBt+VTwvxssdzbAdw= -github.com/iden3/go-iden3-crypto v0.0.16 h1:zN867xiz6HgErXVIV/6WyteGcOukE9gybYTorBMEdsk= -github.com/iden3/go-iden3-crypto v0.0.16/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= +github.com/iden3/go-iden3-core/v2 v2.3.1 h1:ytQqiclnVAIWyRKR2LF31hfz4DGRBD6nMjiPILXGSKk= +github.com/iden3/go-iden3-core/v2 v2.3.1/go.mod h1:8vmG6y8k9VS7iNoxuiKukKbRQFsMyabCc+i8er07zOs= +github.com/iden3/go-iden3-crypto v0.0.17 h1:NdkceRLJo/pI4UpcjVah4lN/a3yzxRUGXqxbWcYh9mY= +github.com/iden3/go-iden3-crypto v0.0.17/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= github.com/iden3/go-jwz/v2 v2.1.1 h1:6274wip59HAi9GkKewG0kKj/WBJeT6T4B+IotQM8IrY= github.com/iden3/go-jwz/v2 v2.1.1/go.mod h1:1mEhNrtAO4eACWZeg9k6T0CxadN4XUkj/dfWUBk3exE= github.com/iden3/go-merkletree-sql/v2 v2.0.4 h1:Dp089P3YNX1BE8+T1tKQHWTtnk84Y/Kr7ZAGTqwscoY= @@ -238,8 +238,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tetratelabs/wazero v1.1.0 h1:EByoAhC+QcYpwSZJSs/aV0uokxPwBgKxfiokSUwAknQ=