feat(browser connect)_: Implementing signTypedData_V4

This commit bundles the personal sign and the signTypedData_V4 sign request in the same command.
The only difference between these two requests is the order of address and challenge in the params array.

What has changed:
1. PersonalSign.. has been renamed to Sign
2. `getPersonalSignParams` renamed to `getSignParams` and implements the parsing for both personal sign and signTypedData_V4
This commit is contained in:
Alex Jbanca 2024-11-19 14:12:08 +02:00
parent 43f355a391
commit e953cb6c95
No known key found for this signature in database
GPG Key ID: 6004079575C21C5D
9 changed files with 339 additions and 190 deletions

View File

@ -30,7 +30,11 @@ func NewAPI(s *Service) *API {
Db: s.db,
ClientHandler: c,
})
r.Register("personal_sign", &commands.PersonalSignCommand{
r.Register("personal_sign", &commands.SignCommand{
Db: s.db,
ClientHandler: c,
})
r.Register("eth_signTypedData_v4", &commands.SignCommand{
Db: s.db,
ClientHandler: c,
})
@ -144,10 +148,10 @@ func (api *API) SendTransactionRejected(args commands.RejectedArgs) error {
return api.c.SendTransactionRejected(args)
}
func (api *API) PersonalSignAccepted(args commands.PersonalSignAcceptedArgs) error {
return api.c.PersonalSignAccepted(args)
func (api *API) SignAccepted(args commands.SignAcceptedArgs) error {
return api.c.SignAccepted(args)
}
func (api *API) PersonalSignRejected(args commands.RejectedArgs) error {
return api.c.PersonalSignRejected(args)
func (api *API) SignRejected(args commands.RejectedArgs) error {
return api.c.SignRejected(args)
}

View File

@ -22,7 +22,7 @@ var (
ErrEmptyAccountsShared = fmt.Errorf("empty accounts were shared by wallet")
ErrRequestAccountsRejectedByUser = fmt.Errorf("request accounts was rejected by user")
ErrSendTransactionRejectedByUser = fmt.Errorf("send transaction was rejected by user")
ErrPersonalSignRejectedByUser = fmt.Errorf("personal sign was rejected by user")
ErrSignRejectedByUser = fmt.Errorf("sign was rejected by user")
ErrEmptyRequestID = fmt.Errorf("empty requestID")
ErrAnotherConnectorOperationIsAwaitingFor = fmt.Errorf("another connector operation is awaiting for user input")
ErrEmptyUrl = fmt.Errorf("empty URL")
@ -34,7 +34,7 @@ type MessageType int
const (
RequestAccountsAccepted MessageType = iota
SendTransactionAccepted
PersonalSignAccepted
SignAccepted
Rejected
)
@ -203,14 +203,14 @@ func (c *ClientSideHandler) SendTransactionRejected(args RejectedArgs) error {
return nil
}
func (c *ClientSideHandler) RequestPersonalSign(dApp signal.ConnectorDApp, challenge, address string) (string, error) {
func (c *ClientSideHandler) RequestSign(dApp signal.ConnectorDApp, challenge, address string, method string) (string, error) {
if !c.setRequestRunning() {
return "", ErrAnotherConnectorOperationIsAwaitingFor
}
defer c.clearRequestRunning()
requestID := c.generateRequestID(dApp)
signal.SendConnectorPersonalSign(dApp, requestID, challenge, address)
signal.SendConnectorSign(dApp, requestID, challenge, address, method)
timeout := time.After(WalletResponseMaxInterval)
@ -218,15 +218,15 @@ func (c *ClientSideHandler) RequestPersonalSign(dApp signal.ConnectorDApp, chall
select {
case msg := <-c.responseChannel:
switch msg.Type {
case PersonalSignAccepted:
response := msg.Data.(PersonalSignAcceptedArgs)
case SignAccepted:
response := msg.Data.(SignAcceptedArgs)
if response.RequestID == requestID {
return response.Signature, nil
}
case Rejected:
response := msg.Data.(RejectedArgs)
if response.RequestID == requestID {
return "", ErrPersonalSignRejectedByUser
return "", ErrSignRejectedByUser
}
}
case <-timeout:
@ -235,16 +235,16 @@ func (c *ClientSideHandler) RequestPersonalSign(dApp signal.ConnectorDApp, chall
}
}
func (c *ClientSideHandler) PersonalSignAccepted(args PersonalSignAcceptedArgs) error {
func (c *ClientSideHandler) SignAccepted(args SignAcceptedArgs) error {
if args.RequestID == "" {
return ErrEmptyRequestID
}
c.responseChannel <- Message{Type: PersonalSignAccepted, Data: args}
c.responseChannel <- Message{Type: SignAccepted, Data: args}
return nil
}
func (c *ClientSideHandler) PersonalSignRejected(args RejectedArgs) error {
func (c *ClientSideHandler) SignRejected(args RejectedArgs) error {
if args.RequestID == "" {
return ErrEmptyRequestID
}

View File

@ -1,153 +0,0 @@
package commands
import (
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/signal"
)
func preparePersonalSignRequest(dApp signal.ConnectorDApp, challenge, address string) (RPCRequest, error) {
return ConstructRPCRequest("personal_sign", []interface{}{challenge, address}, &dApp)
}
func TestFailToPersonalSignWithMissingDAppFields(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
// Missing DApp fields
request, err := ConstructRPCRequest("personal_sign", []interface{}{}, nil)
assert.NoError(t, err)
result, err := state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrRequestMissingDAppData, err)
assert.Empty(t, result)
}
func TestFailToPersonalSignForUnpermittedDApp(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
request, err := preparePersonalSignRequest(testDAppData,
"0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e",
"0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7",
)
assert.NoError(t, err)
result, err := state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrDAppIsNotPermittedByUser, err)
assert.Empty(t, result)
}
func TestFailToPersonalSignWithoutParams(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
request, err := ConstructRPCRequest("personal_sign", nil, &testDAppData)
assert.NoError(t, err)
result, err := state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrEmptyRPCParams, err)
assert.Empty(t, result)
}
func TestFailToPersonalSignWithSignalTimout(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
request, err := preparePersonalSignRequest(testDAppData,
"0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e",
"0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7",
)
assert.NoError(t, err)
backupWalletResponseMaxInterval := WalletResponseMaxInterval
WalletResponseMaxInterval = 1 * time.Millisecond
_, err = state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrWalletResponseTimeout, err)
WalletResponseMaxInterval = backupWalletResponseMaxInterval
}
func TestPersonalSignWithSignalAccepted(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
fakedSignature := "0x051"
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
challenge := "0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e"
address := "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7"
request, err := preparePersonalSignRequest(testDAppData, challenge, address)
assert.NoError(t, err)
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
var evt EventType
err := json.Unmarshal(s, &evt)
assert.NoError(t, err)
switch evt.Type {
case signal.EventConnectorPersonalSign:
var ev signal.ConnectorPersonalSignSignal
err := json.Unmarshal(evt.Event, &ev)
assert.NoError(t, err)
assert.Equal(t, ev.Challenge, challenge)
assert.Equal(t, ev.Address, address)
err = state.handler.PersonalSignAccepted(PersonalSignAcceptedArgs{
Signature: fakedSignature,
RequestID: ev.RequestID,
})
assert.NoError(t, err)
}
}))
t.Cleanup(signal.ResetMobileSignalHandler)
response, err := state.cmd.Execute(state.ctx, request)
assert.NoError(t, err)
assert.Equal(t, response, fakedSignature)
}
func TestPersonalSignWithSignalRejected(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
challenge := "0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e"
address := "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7"
request, err := preparePersonalSignRequest(testDAppData, challenge, address)
assert.NoError(t, err)
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
var evt EventType
err := json.Unmarshal(s, &evt)
assert.NoError(t, err)
switch evt.Type {
case signal.EventConnectorPersonalSign:
var ev signal.ConnectorPersonalSignSignal
err := json.Unmarshal(evt.Event, &ev)
assert.NoError(t, err)
err = state.handler.PersonalSignRejected(RejectedArgs{
RequestID: ev.RequestID,
})
assert.NoError(t, err)
}
}))
t.Cleanup(signal.ResetMobileSignalHandler)
_, err = state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrPersonalSignRejectedByUser, err)
}

View File

@ -17,6 +17,7 @@ const (
Method_EthRequestAccounts = "eth_requestAccounts"
Method_EthChainId = "eth_chainId"
Method_PersonalSign = "personal_sign"
Method_SignTypedDataV4 = "eth_signTypedData_v4"
Method_EthSendTransaction = "eth_sendTransaction"
Method_RequestPermissions = "wallet_requestPermissions"
Method_RevokePermissions = "wallet_revokePermissions"
@ -56,7 +57,7 @@ type SendTransactionAcceptedArgs struct {
Hash types.Hash `json:"hash"`
}
type PersonalSignAcceptedArgs struct {
type SignAcceptedArgs struct {
RequestID string `json:"requestId"`
Signature string `json:"signature"`
}
@ -79,9 +80,9 @@ type ClientSideHandlerInterface interface {
SendTransactionAccepted(args SendTransactionAcceptedArgs) error
SendTransactionRejected(args RejectedArgs) error
RequestPersonalSign(dApp signal.ConnectorDApp, challenge, address string) (string, error)
PersonalSignAccepted(args PersonalSignAcceptedArgs) error
PersonalSignRejected(args RejectedArgs) error
RequestSign(dApp signal.ConnectorDApp, challenge, address string, method string) (string, error)
SignAccepted(args SignAcceptedArgs) error
SignRejected(args RejectedArgs) error
}
type NetworkManagerInterface interface {

View File

@ -12,19 +12,25 @@ import (
var (
ErrInvalidParamsStructure = errors.New("invalid params structure")
ErrInvalidMethod = errors.New("invalid method")
)
type PersonalSignCommand struct {
type SignCommand struct {
Db *sql.DB
ClientHandler ClientSideHandlerInterface
}
type PersonalSignParams struct {
type SignParams struct {
Challenge string `json:"challenge"`
Address string `json:"address"`
Method string `json:"method"`
}
func (r *RPCRequest) getPersonalSignParams() (*PersonalSignParams, error) {
func (r *RPCRequest) getSignParams() (*SignParams, error) {
if r.Method != Method_PersonalSign && r.Method != Method_SignTypedDataV4 {
return nil, ErrInvalidMethod
}
if r.Params == nil || len(r.Params) == 0 {
return nil, ErrEmptyRPCParams
}
@ -33,31 +39,40 @@ func (r *RPCRequest) getPersonalSignParams() (*PersonalSignParams, error) {
return nil, ErrInvalidParamsStructure
}
challengeIndex := 0
addressIndex := 1
if r.Method == Method_SignTypedDataV4 {
challengeIndex = 1
addressIndex = 0
}
// Extract the Challenge and Address fields from paramsArray
challenge, ok := r.Params[0].(string)
challenge, ok := r.Params[challengeIndex].(string)
if !ok {
return nil, fmt.Errorf("missing or invalid 'challenge' field")
}
address, ok := r.Params[1].(string)
address, ok := r.Params[addressIndex].(string)
if !ok {
return nil, fmt.Errorf("missing or invalid 'address' field")
}
// Create and return the PersonalSignParams
return &PersonalSignParams{
return &SignParams{
Challenge: challenge,
Address: address,
Method: r.Method,
}, nil
}
func (c *PersonalSignCommand) Execute(ctx context.Context, request RPCRequest) (interface{}, error) {
func (c *SignCommand) Execute(ctx context.Context, request RPCRequest) (interface{}, error) {
err := request.Validate()
if err != nil {
return "", err
}
params, err := request.getPersonalSignParams()
params, err := request.getSignParams()
if err != nil {
return "", err
}
@ -71,9 +86,9 @@ func (c *PersonalSignCommand) Execute(ctx context.Context, request RPCRequest) (
return "", ErrDAppIsNotPermittedByUser
}
return c.ClientHandler.RequestPersonalSign(signal.ConnectorDApp{
return c.ClientHandler.RequestSign(signal.ConnectorDApp{
URL: request.URL,
Name: request.Name,
IconURL: request.IconURL,
}, params.Challenge, params.Address)
}, params.Challenge, params.Address, params.Method)
}

View File

@ -0,0 +1,275 @@
package commands
import (
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/signal"
)
func preparePersonalSignRequest(dApp signal.ConnectorDApp, challenge, address string) (RPCRequest, error) {
return ConstructRPCRequest("personal_sign", []interface{}{challenge, address}, &dApp)
}
func prepareTypedDataV4SignRequest(dApp signal.ConnectorDApp, challenge, address string) (RPCRequest, error) {
return ConstructRPCRequest("eth_signTypedData_v4", []interface{}{address, challenge}, &dApp)
}
func TestFailToPersonalSignWithMissingDAppFields(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
// Missing DApp fields
request, err := ConstructRPCRequest("personal_sign", []interface{}{}, nil)
assert.NoError(t, err)
result, err := state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrRequestMissingDAppData, err)
assert.Empty(t, result)
}
func TestFailToPersonalSignForUnpermittedDApp(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
request, err := preparePersonalSignRequest(testDAppData,
"0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e",
"0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7",
)
assert.NoError(t, err)
result, err := state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrDAppIsNotPermittedByUser, err)
assert.Empty(t, result)
}
func TestFailToPersonalSignWithoutParams(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
request, err := ConstructRPCRequest("personal_sign", nil, &testDAppData)
assert.NoError(t, err)
result, err := state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrEmptyRPCParams, err)
assert.Empty(t, result)
}
func TestFailToPersonalSignWithSignalTimout(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
request, err := preparePersonalSignRequest(testDAppData,
"0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e",
"0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7",
)
assert.NoError(t, err)
backupWalletResponseMaxInterval := WalletResponseMaxInterval
WalletResponseMaxInterval = 1 * time.Millisecond
_, err = state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrWalletResponseTimeout, err)
WalletResponseMaxInterval = backupWalletResponseMaxInterval
}
func TestPersonalSignWithSignalAccepted(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
fakedSignature := "0x051"
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
challenge := "0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e"
address := "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7"
request, err := preparePersonalSignRequest(testDAppData, challenge, address)
assert.NoError(t, err)
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
var evt EventType
err := json.Unmarshal(s, &evt)
assert.NoError(t, err)
switch evt.Type {
case signal.EventConnectorSign:
var ev signal.ConnectorSignSignal
err := json.Unmarshal(evt.Event, &ev)
assert.NoError(t, err)
assert.Equal(t, ev.Challenge, challenge)
assert.Equal(t, ev.Address, address)
err = state.handler.SignAccepted(SignAcceptedArgs{
Signature: fakedSignature,
RequestID: ev.RequestID,
})
assert.NoError(t, err)
}
}))
t.Cleanup(signal.ResetMobileSignalHandler)
response, err := state.cmd.Execute(state.ctx, request)
assert.NoError(t, err)
assert.Equal(t, response, fakedSignature)
}
func TestPersonalSignWithSignalRejected(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
challenge := "0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e"
address := "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7"
request, err := preparePersonalSignRequest(testDAppData, challenge, address)
assert.NoError(t, err)
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
var evt EventType
err := json.Unmarshal(s, &evt)
assert.NoError(t, err)
switch evt.Type {
case signal.EventConnectorSign:
var ev signal.ConnectorSignSignal
err := json.Unmarshal(evt.Event, &ev)
assert.NoError(t, err)
err = state.handler.SignRejected(RejectedArgs{
RequestID: ev.RequestID,
})
assert.NoError(t, err)
}
}))
t.Cleanup(signal.ResetMobileSignalHandler)
_, err = state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrSignRejectedByUser, err)
}
func TestTypedDataV4SignRequestWithSignalAccepted(t *testing.T) {
state, close := setupCommand(t, Method_SignTypedDataV4)
t.Cleanup(close)
fakedSignature := "0x051"
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
challenge := "{\"domain\":{\"chainId\":\"1\",\"name\":\"Ether Mail\",\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\",\"version\":\"1\"},\"message\":{\"contents\":\"Hello, Bob!\",\"from\":{\"name\":\"Cow\",\"wallets\":[\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF\"]},\"to\":[{\"name\":\"Bob\",\"wallets\":[\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\",\"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57\",\"0xB0B0b0b0b0b0B000000000000000000000000000\"]}],\"attachment\":\"0x\"},\"primaryType\":\"Mail\",\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Group\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"members\",\"type\":\"Person[]\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person[]\"},{\"name\":\"contents\",\"type\":\"string\"},{\"name\":\"attachment\",\"type\":\"bytes\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallets\",\"type\":\"address[]\"}]}}"
address := "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7"
request, err := prepareTypedDataV4SignRequest(testDAppData, challenge, address)
assert.NoError(t, err)
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
var evt EventType
err := json.Unmarshal(s, &evt)
assert.NoError(t, err)
switch evt.Type {
case signal.EventConnectorSign:
var ev signal.ConnectorSignSignal
err := json.Unmarshal(evt.Event, &ev)
assert.NoError(t, err)
assert.Equal(t, ev.Challenge, challenge)
assert.Equal(t, ev.Address, address)
err = state.handler.SignAccepted(SignAcceptedArgs{
Signature: fakedSignature,
RequestID: ev.RequestID,
})
assert.NoError(t, err)
}
}))
t.Cleanup(signal.ResetMobileSignalHandler)
response, err := state.cmd.Execute(state.ctx, request)
assert.NoError(t, err)
assert.Equal(t, response, fakedSignature)
}
func TestTypedDataV4SignRequestWithSignalRejected(t *testing.T) {
state, close := setupCommand(t, Method_SignTypedDataV4)
t.Cleanup(close)
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
challenge := "{\"domain\":{\"chainId\":\"1\",\"name\":\"Ether Mail\",\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\",\"version\":\"1\"},\"message\":{\"contents\":\"Hello, Bob!\",\"from\":{\"name\":\"Cow\",\"wallets\":[\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF\"]},\"to\":[{\"name\":\"Bob\",\"wallets\":[\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\",\"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57\",\"0xB0B0b0b0b0b0B000000000000000000000000000\"]}],\"attachment\":\"0x\"},\"primaryType\":\"Mail\",\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Group\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"members\",\"type\":\"Person[]\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person[]\"},{\"name\":\"contents\",\"type\":\"string\"},{\"name\":\"attachment\",\"type\":\"bytes\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallets\",\"type\":\"address[]\"}]}}"
address := "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7"
request, err := preparePersonalSignRequest(testDAppData, challenge, address)
assert.NoError(t, err)
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
var evt EventType
err := json.Unmarshal(s, &evt)
assert.NoError(t, err)
switch evt.Type {
case signal.EventConnectorSign:
var ev signal.ConnectorSignSignal
err := json.Unmarshal(evt.Event, &ev)
assert.NoError(t, err)
err = state.handler.SignRejected(RejectedArgs{
RequestID: ev.RequestID,
})
assert.NoError(t, err)
}
}))
t.Cleanup(signal.ResetMobileSignalHandler)
_, err = state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrSignRejectedByUser, err)
}
func TestUnsupportedSignMethod(t *testing.T) {
state, close := setupCommand(t, Method_PersonalSign)
t.Cleanup(close)
err := PersistDAppData(state.walletDb, testDAppData, types.Address{0x01}, uint64(0x1))
assert.NoError(t, err)
challenge := "0x506c65617365207369676e2074686973206d65737361676520746f20636f6e6669726d20796f7572206964656e746974792e"
address := "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7"
request, err := preparePersonalSignRequest(testDAppData, challenge, address)
assert.NoError(t, err)
request.Method = "eth_signTypedData"
fakedSignature := "0x051"
signal.SetMobileSignalHandler(signal.MobileSignalHandler(func(s []byte) {
var evt EventType
err := json.Unmarshal(s, &evt)
assert.NoError(t, err)
switch evt.Type {
case signal.EventConnectorSign:
var ev signal.ConnectorSignSignal
err := json.Unmarshal(evt.Event, &ev)
assert.NoError(t, err)
assert.Equal(t, ev.Challenge, challenge)
assert.Equal(t, ev.Address, address)
err = state.handler.SignAccepted(SignAcceptedArgs{
Signature: fakedSignature,
RequestID: ev.RequestID,
})
assert.NoError(t, err)
}
}))
t.Cleanup(signal.ResetMobileSignalHandler)
response, err := state.cmd.Execute(state.ctx, request)
assert.Equal(t, ErrInvalidMethod, err)
assert.Equal(t, response, "")
}

View File

@ -102,7 +102,12 @@ func setupCommand(t *testing.T, method string) (state testState, close func()) {
NetworkManager: networkManager,
}
case Method_PersonalSign:
state.cmd = &PersonalSignCommand{
state.cmd = &SignCommand{
Db: state.walletDb,
ClientHandler: state.handler,
}
case Method_SignTypedDataV4:
state.cmd = &SignCommand{
Db: state.walletDb,
ClientHandler: state.handler,
}

View File

@ -60,12 +60,12 @@ func TestRequestAccountsSwitchChainAndSendTransactionFlow(t *testing.T) {
Hash: expectedHash,
})
assert.NoError(t, err)
case signal.EventConnectorPersonalSign:
var ev signal.ConnectorPersonalSignSignal
case signal.EventConnectorSign:
var ev signal.ConnectorSignSignal
err := json.Unmarshal(evt.Event, &ev)
assert.NoError(t, err)
err = state.api.PersonalSignAccepted(commands.PersonalSignAcceptedArgs{
err = state.api.SignAccepted(commands.SignAcceptedArgs{
RequestID: ev.RequestID,
Signature: expectedSignature,
})

View File

@ -7,7 +7,7 @@ import (
const (
EventConnectorSendRequestAccounts = "connector.sendRequestAccounts"
EventConnectorSendTransaction = "connector.sendTransaction"
EventConnectorPersonalSign = "connector.personalSign"
EventConnectorSign = "connector.sign"
EventConnectorDAppPermissionGranted = "connector.dAppPermissionGranted"
EventConnectorDAppPermissionRevoked = "connector.dAppPermissionRevoked"
EventConnectorDAppChainIdSwitched = "connector.dAppChainIdSwitched"
@ -39,11 +39,12 @@ type ConnectorSendDappPermissionGrantedSignal struct {
SharedAccount types.Address `json:"sharedAccount"`
}
type ConnectorPersonalSignSignal struct {
type ConnectorSignSignal struct {
ConnectorDApp
RequestID string `json:"requestId"`
Challenge string `json:"challenge"`
Address string `json:"address"`
Method string `json:"method"`
}
type ConnectorDAppChainIdSwitchedSignal struct {
@ -67,12 +68,13 @@ func SendConnectorSendTransaction(dApp ConnectorDApp, chainID uint64, txArgs str
})
}
func SendConnectorPersonalSign(dApp ConnectorDApp, requestID, challenge, address string) {
send(EventConnectorPersonalSign, ConnectorPersonalSignSignal{
func SendConnectorSign(dApp ConnectorDApp, requestID, challenge, address string, method string) {
send(EventConnectorSign, ConnectorSignSignal{
ConnectorDApp: dApp,
RequestID: requestID,
Challenge: challenge,
Address: address,
Method: method,
})
}