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:
parent
43f355a391
commit
e953cb6c95
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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, "")
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue