From 35e187b8f7527a4420a0b2c27ccc4e1c03abcc74 Mon Sep 17 00:00:00 2001 From: shwoop Date: Wed, 2 Jul 2025 15:33:48 +0200 Subject: [PATCH] passing test --- rpc/server.go | 20 ++++++++++ signer/core/signed_data_test.go | 23 ++++++++++-- signer/core/siwevalidation.go | 39 +++++++++++--------- signer/core/testdata/siwe/valid_eip1271.json | 16 +++++++- 4 files changed, 75 insertions(+), 23 deletions(-) diff --git a/rpc/server.go b/rpc/server.go index 599e31fb41..9596477a85 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -256,3 +256,23 @@ func PeerInfoFromContext(ctx context.Context) PeerInfo { info, _ := ctx.Value(peerInfoContextKey{}).(PeerInfo) return info } + +// ContextWithMockPeerInfo is a helper function to create a context with a mock peer info. +// It is used in tests to simulate a peer info. +func ContextWithMockPeerInfo(ctx context.Context, transport, source, account string) context.Context { + peerInfo := PeerInfo{ + Transport: transport, + HTTP: struct { + Version string + UserAgent string + Origin string + Host string + }{ + Version: "1.1", + UserAgent: "test", + Origin: source, + Host: "test", + }, + } + return context.WithValue(ctx, peerInfoContextKey{}, peerInfo) +} \ No newline at end of file diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index a7678186bd..15480f28fb 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -17,6 +17,7 @@ package core_test import ( + "cmp" "bytes" "context" "encoding/json" @@ -32,6 +33,7 @@ import ( "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/rpc" "github.com/ethereum/go-ethereum/signer/core" "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/stretchr/testify/require" @@ -1068,14 +1070,23 @@ func TestSignInWithEtheriumValid(t *testing.T) { testFiles, err := os.ReadDir(filepath.Join("testdata", "siwe")) require.NoError(t, err) - var messages map[string]string + type TestData struct { + Msg string `json:"msg"` + Account string `json:"account"` + RequestContext struct { + Transport string `json:"transport"` + Source string `json:"source"` + Account string `json:"account"` + } `json:"request_context"` + } + var messages map[string]TestData var expectingWarning bool for _, fInfo := range testFiles { if !strings.HasSuffix(fInfo.Name(), "json") { continue } - if fInfo.Name() != "warning_uris.json" { + if fInfo.Name() != "valid_eip1271.json" { continue } expectingWarning = strings.HasPrefix(fInfo.Name(), "warning") @@ -1086,7 +1097,7 @@ func TestSignInWithEtheriumValid(t *testing.T) { err = json.Unmarshal(jsonFile, &messages) require.NoError(t, err) - for testName, message := range messages { + for testName, testData := range messages { t.Run(testName, func(t *testing.T) { t.Parallel() @@ -1098,9 +1109,13 @@ func TestSignInWithEtheriumValid(t *testing.T) { require.NoError(t, err) a := common.NewMixedcaseAddress(list[0]) + ctx := rpc.ContextWithMockPeerInfo(context.Background(), testData.RequestContext.Transport, testData.RequestContext.Source, testData.Account) + account := cmp.Or(testData.Account, a.Address().Hex()) + message := strings.ReplaceAll(testData.Msg, "{{Account}}", account) + control.approveCh <- "Y" control.inputCh <- "a_long_password" - signature, err := api.SignData(context.Background(), apitypes.TextPlain.Mime, a, hexutil.Encode([]byte(message))) + signature, err := api.SignData(ctx, apitypes.TextPlain.Mime, a, hexutil.Encode([]byte(message))) if expectingWarning { // todo: check UI for warning message diff --git a/signer/core/siwevalidation.go b/signer/core/siwevalidation.go index 51eb08920a..f0d4aacd70 100644 --- a/signer/core/siwevalidation.go +++ b/signer/core/siwevalidation.go @@ -25,24 +25,27 @@ import ( "github.com/ethereum/go-ethereum/common" ) +// Message size +var messageSize = `(?:\d+)` + // Regular expression to match SIWE messages // Scheme (optional) -var scheme = `(?:[a-zA-Z][a-zA-Z0-9+\-.]*://)?` +var scheme = `([a-zA-Z][a-zA-Z0-9+\-.]*://)?` // Domain -var domain = `(?:[^ ]+)` +var domain = `([^ ]+)` // Static message var wantsMsg = ` wants you to sign in with your Ethereum account:\n` // Ethereum address (with basic 0x prefix + 40 hex digits) -var address = `(?:0x[a-fA-F0-9]{40})\n` +var address = `(0x[a-fA-F0-9]{40})\n` // Optional statement (any line not containing "\n\n") var statement = `(?:[^\n]+\n)?` // URI -var uri = `URI: (.+)\n` +var uri = `URI: (?:.+)\n` // Version var version = `Version: 1\n` @@ -51,25 +54,25 @@ var version = `Version: 1\n` var chainID = `Chain ID: (\d+)\n` // Nonce (min 8 alphanumeric characters) -var nonce = `Nonce: [a-zA-Z0-9]{8,}\n` +var nonce = `Nonce: (?:[a-zA-Z0-9]{8,})\n` // Issued At (RFC 3339 date-time) -var issuedAt = `Issued At: ([0-9T:\-+.Z]+)` +var issuedAt = `Issued At: (?:[0-9T:\-+.Z]+)` // Optional Expiration Time -var expiration = `(?:\nExpiration Time: ([0-9T:\-+.Z]+))?` +var expiration = `(?:\nExpiration Time: (?:[0-9T:\-+.Z]+))?` // Optional Not Before -var notBefore = `(?:\nNot Before: ([0-9T:\-+.Z]+))?` +var notBefore = `(?:\nNot Before: (?:[0-9T:\-+.Z]+))?` // Optional Request ID -var requestID = `(?:\nRequest ID: ([^\n]+))?` +var requestID = `(?:\nRequest ID: (?:[^\n]+))?` // Optional Resources var resources = `(?:\nResources:(?:\n- .+)+)?` // SIWE Message Regex -var siweMessageRegex = regexp.MustCompile(`(?m)^` + scheme + domain + wantsMsg + +var siweMessageRegex = regexp.MustCompile(`(?m)^` + messageSize + scheme + domain + wantsMsg + address + `\n` + statement + `\n` + uri + version + chainID + nonce + issuedAt + expiration + notBefore + requestID + resources + `$`) @@ -85,18 +88,19 @@ func validateSIWE(req *SignDataRequest) error { if !strings.Contains(s, "wants you to sign in with your Ethereum account") { continue } + patterns := siweMessageRegex.FindStringSubmatch(s) - if len(patterns) != 15 { + if patterns == nil { return ErrMalformedSIWEMEssage } scheme := "https" - if patterns[0] != "" { - scheme = patterns[0] + if patterns[1] != "" { + scheme = patterns[1] } - if err := validateDomain(req, scheme, patterns[1]); err != nil { + if err := validateDomain(req, scheme, patterns[2]); err != nil { return err } - if err := validateAddress(req, patterns[2]); err != nil { + if err := validateAddress(req, patterns[3]); err != nil { return err } } @@ -105,8 +109,9 @@ func validateSIWE(req *SignDataRequest) error { func validateDomain(request *SignDataRequest, scheme, domain string) error { siweOrigin := fmt.Sprintf("%s://%s", scheme, domain) - if siweOrigin != request.Meta.Origin { - return fmt.Errorf("sign in request domain (%s) does not match source: %s", siweOrigin, request.Meta.Origin) + requestOrigin := fmt.Sprintf("%s://%s", request.Meta.Scheme, request.Meta.Origin) + if siweOrigin != requestOrigin { + return fmt.Errorf("sign in request domain (%s) does not match source: %s", siweOrigin, requestOrigin) } return nil } diff --git a/signer/core/testdata/siwe/valid_eip1271.json b/signer/core/testdata/siwe/valid_eip1271.json index 85bcf181a6..9096eaa934 100644 --- a/signer/core/testdata/siwe/valid_eip1271.json +++ b/signer/core/testdata/siwe/valid_eip1271.json @@ -1,4 +1,16 @@ { - "argent": "localhost:4361 wants you to sign in with your Ethereum account:\n0xa5b3A53800cD49669F34DE80f2C569c6D4Ca3009\n\nSIWE Notepad Example\n\nURI: http://localhost:4361\nVersion: 1\nChain ID: 1\nNonce: FbYd6TNB4m0IUHDG7\nIssued At: 2022-04-19T18:55:04.444Z", - "loopring": "localhost:4361 wants you to sign in with your Ethereum account:\n0x0e565A6dFc43DE21455a67bbF196f7F7b15447A7\n\nSIWE Notepad Example\n\nURI: http://localhost:4361\nVersion: 1\nChain ID: 1\nNonce: b19JyMHnM0Jdm20as\nIssued At: 2022-04-19T18:57:09.490Z" + "argent": { + "msg": "localhost:4361 wants you to sign in with your Ethereum account:\n{{Account}}\n\nSIWE Notepad Example\n\nURI: http://localhost:4361\nVersion: 1\nChain ID: 1\nNonce: FbYd6TNB4m0IUHDG7\nIssued At: 2022-04-19T18:55:04.444Z", + "request_context": { + "transport": "https", + "source": "localhost:4361" + } + }, + "loopring": { + "msg": "localhost:4361 wants you to sign in with your Ethereum account:\n{{Account}}\n\nSIWE Notepad Example\n\nURI: http://localhost:4361\nVersion: 1\nChain ID: 1\nNonce: b19JyMHnM0Jdm20as\nIssued At: 2022-04-19T18:57:09.490Z", + "request_context": { + "transport": "https", + "source": "localhost:4361" + } + } } \ No newline at end of file