passing test

This commit is contained in:
shwoop 2025-07-02 15:33:48 +02:00
parent 5c54198a68
commit 35e187b8f7
No known key found for this signature in database
GPG key ID: 95A35B68C1E5F95A
4 changed files with 75 additions and 23 deletions

View file

@ -256,3 +256,23 @@ func PeerInfoFromContext(ctx context.Context) PeerInfo {
info, _ := ctx.Value(peerInfoContextKey{}).(PeerInfo) info, _ := ctx.Value(peerInfoContextKey{}).(PeerInfo)
return info 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)
}

View file

@ -17,6 +17,7 @@
package core_test package core_test
import ( import (
"cmp"
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
@ -32,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto" "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"
"github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -1068,14 +1070,23 @@ func TestSignInWithEtheriumValid(t *testing.T) {
testFiles, err := os.ReadDir(filepath.Join("testdata", "siwe")) testFiles, err := os.ReadDir(filepath.Join("testdata", "siwe"))
require.NoError(t, err) 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 var expectingWarning bool
for _, fInfo := range testFiles { for _, fInfo := range testFiles {
if !strings.HasSuffix(fInfo.Name(), "json") { if !strings.HasSuffix(fInfo.Name(), "json") {
continue continue
} }
if fInfo.Name() != "warning_uris.json" { if fInfo.Name() != "valid_eip1271.json" {
continue continue
} }
expectingWarning = strings.HasPrefix(fInfo.Name(), "warning") expectingWarning = strings.HasPrefix(fInfo.Name(), "warning")
@ -1086,7 +1097,7 @@ func TestSignInWithEtheriumValid(t *testing.T) {
err = json.Unmarshal(jsonFile, &messages) err = json.Unmarshal(jsonFile, &messages)
require.NoError(t, err) require.NoError(t, err)
for testName, message := range messages { for testName, testData := range messages {
t.Run(testName, func(t *testing.T) { t.Run(testName, func(t *testing.T) {
t.Parallel() t.Parallel()
@ -1098,9 +1109,13 @@ func TestSignInWithEtheriumValid(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
a := common.NewMixedcaseAddress(list[0]) 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.approveCh <- "Y"
control.inputCh <- "a_long_password" 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 { if expectingWarning {
// todo: check UI for warning message // todo: check UI for warning message

View file

@ -25,24 +25,27 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
// Message size
var messageSize = `(?:\d+)`
// Regular expression to match SIWE messages // Regular expression to match SIWE messages
// Scheme (optional) // Scheme (optional)
var scheme = `(?:[a-zA-Z][a-zA-Z0-9+\-.]*://)?` var scheme = `([a-zA-Z][a-zA-Z0-9+\-.]*://)?`
// Domain // Domain
var domain = `(?:[^ ]+)` var domain = `([^ ]+)`
// Static message // Static message
var wantsMsg = ` wants you to sign in with your Ethereum account:\n` var wantsMsg = ` wants you to sign in with your Ethereum account:\n`
// Ethereum address (with basic 0x prefix + 40 hex digits) // 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") // Optional statement (any line not containing "\n\n")
var statement = `(?:[^\n]+\n)?` var statement = `(?:[^\n]+\n)?`
// URI // URI
var uri = `URI: (.+)\n` var uri = `URI: (?:.+)\n`
// Version // Version
var version = `Version: 1\n` var version = `Version: 1\n`
@ -51,25 +54,25 @@ var version = `Version: 1\n`
var chainID = `Chain ID: (\d+)\n` var chainID = `Chain ID: (\d+)\n`
// Nonce (min 8 alphanumeric characters) // 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) // Issued At (RFC 3339 date-time)
var issuedAt = `Issued At: ([0-9T:\-+.Z]+)` var issuedAt = `Issued At: (?:[0-9T:\-+.Z]+)`
// Optional Expiration Time // Optional Expiration Time
var expiration = `(?:\nExpiration Time: ([0-9T:\-+.Z]+))?` var expiration = `(?:\nExpiration Time: (?:[0-9T:\-+.Z]+))?`
// Optional Not Before // Optional Not Before
var notBefore = `(?:\nNot Before: ([0-9T:\-+.Z]+))?` var notBefore = `(?:\nNot Before: (?:[0-9T:\-+.Z]+))?`
// Optional Request ID // Optional Request ID
var requestID = `(?:\nRequest ID: ([^\n]+))?` var requestID = `(?:\nRequest ID: (?:[^\n]+))?`
// Optional Resources // Optional Resources
var resources = `(?:\nResources:(?:\n- .+)+)?` var resources = `(?:\nResources:(?:\n- .+)+)?`
// SIWE Message Regex // SIWE Message Regex
var siweMessageRegex = regexp.MustCompile(`(?m)^` + scheme + domain + wantsMsg + var siweMessageRegex = regexp.MustCompile(`(?m)^` + messageSize + scheme + domain + wantsMsg +
address + `\n` + statement + `\n` + address + `\n` + statement + `\n` +
uri + version + chainID + nonce + issuedAt + uri + version + chainID + nonce + issuedAt +
expiration + notBefore + requestID + resources + `$`) 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") { if !strings.Contains(s, "wants you to sign in with your Ethereum account") {
continue continue
} }
patterns := siweMessageRegex.FindStringSubmatch(s) patterns := siweMessageRegex.FindStringSubmatch(s)
if len(patterns) != 15 { if patterns == nil {
return ErrMalformedSIWEMEssage return ErrMalformedSIWEMEssage
} }
scheme := "https" scheme := "https"
if patterns[0] != "" { if patterns[1] != "" {
scheme = patterns[0] scheme = patterns[1]
} }
if err := validateDomain(req, scheme, patterns[1]); err != nil { if err := validateDomain(req, scheme, patterns[2]); err != nil {
return err return err
} }
if err := validateAddress(req, patterns[2]); err != nil { if err := validateAddress(req, patterns[3]); err != nil {
return err return err
} }
} }
@ -105,8 +109,9 @@ func validateSIWE(req *SignDataRequest) error {
func validateDomain(request *SignDataRequest, scheme, domain string) error { func validateDomain(request *SignDataRequest, scheme, domain string) error {
siweOrigin := fmt.Sprintf("%s://%s", scheme, domain) siweOrigin := fmt.Sprintf("%s://%s", scheme, domain)
if siweOrigin != request.Meta.Origin { requestOrigin := fmt.Sprintf("%s://%s", request.Meta.Scheme, request.Meta.Origin)
return fmt.Errorf("sign in request domain (%s) does not match source: %s", siweOrigin, request.Meta.Origin) if siweOrigin != requestOrigin {
return fmt.Errorf("sign in request domain (%s) does not match source: %s", siweOrigin, requestOrigin)
} }
return nil return nil
} }

View file

@ -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", "argent": {
"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" "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"
}
}
} }