2023-01-06 12:21:14 +00:00
package pairing
import (
"context"
"encoding/json"
"path/filepath"
"testing"
2023-05-12 08:31:34 +00:00
"time"
2023-04-19 22:59:09 +00:00
2023-07-12 09:46:56 +00:00
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/protocol/tt"
2023-01-06 12:21:14 +00:00
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/status-im/status-go/account/generator"
"github.com/status-im/status-go/api"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/multiaccounts"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/params"
2023-05-12 08:31:34 +00:00
"github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/identity"
2023-01-06 12:21:14 +00:00
"github.com/status-im/status-go/protocol/identity/alias"
2023-05-12 08:31:34 +00:00
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/requests"
2023-01-06 12:21:14 +00:00
"github.com/status-im/status-go/services/browsers"
"github.com/status-im/status-go/sqlite"
)
2023-03-23 11:44:15 +00:00
const (
pathWalletRoot = "m/44'/60'/0'/0"
pathEIP1581 = "m/43'/60'/1581'"
pathDefaultChat = pathEIP1581 + "/0'/0"
pathDefaultWallet = pathWalletRoot + "/0"
currentNetwork = "mainnet_rpc"
2023-04-19 22:59:09 +00:00
socialLinkURL = "https://github.com/status-im"
2023-04-26 15:37:18 +00:00
ensUsername = "bob.stateofus.eth"
ensChainID = 1
2023-05-12 08:31:34 +00:00
publicChatID = "localpairtest"
2023-03-23 11:44:15 +00:00
)
2023-01-06 12:21:14 +00:00
var paths = [ ] string { pathWalletRoot , pathEIP1581 , pathDefaultChat , pathDefaultWallet }
func TestSyncDeviceSuite ( t * testing . T ) {
suite . Run ( t , new ( SyncDeviceSuite ) )
}
type SyncDeviceSuite struct {
suite . Suite
2023-07-12 09:46:56 +00:00
logger * zap . Logger
2023-01-06 12:21:14 +00:00
password string
clientAsSenderTmpdir string
clientAsReceiverTmpdir string
2023-07-12 09:46:56 +00:00
pairThreeDevicesTmpdir string
2023-01-06 12:21:14 +00:00
}
func ( s * SyncDeviceSuite ) SetupTest ( ) {
2023-07-12 09:46:56 +00:00
s . logger = tt . MustCreateTestLogger ( )
2023-01-06 12:21:14 +00:00
s . password = "password"
2023-04-26 20:39:51 +00:00
s . clientAsSenderTmpdir = s . T ( ) . TempDir ( )
s . clientAsReceiverTmpdir = s . T ( ) . TempDir ( )
2023-07-12 09:46:56 +00:00
s . pairThreeDevicesTmpdir = s . T ( ) . TempDir ( )
2023-01-06 12:21:14 +00:00
}
func ( s * SyncDeviceSuite ) prepareBackendWithAccount ( tmpdir string ) * api . GethStatusBackend {
backend := s . prepareBackendWithoutAccount ( tmpdir )
accountManager := backend . AccountManager ( )
generator := accountManager . AccountsGenerator ( )
generatedAccountInfos , err := generator . GenerateAndDeriveAddresses ( 12 , 1 , "" , paths )
require . NoError ( s . T ( ) , err )
generatedAccountInfo := generatedAccountInfos [ 0 ]
account := multiaccounts . Account {
KeyUID : generatedAccountInfo . KeyUID ,
KDFIterations : sqlite . ReducedKDFIterationsNumber ,
}
err = accountManager . InitKeystore ( filepath . Join ( tmpdir , keystoreDir , account . KeyUID ) )
require . NoError ( s . T ( ) , err )
err = backend . OpenAccounts ( )
require . NoError ( s . T ( ) , err )
derivedAddresses := generatedAccountInfo . Derived
_ , err = generator . StoreDerivedAccounts ( generatedAccountInfo . ID , s . password , paths )
require . NoError ( s . T ( ) , err )
settings , err := defaultSettings ( generatedAccountInfo . GeneratedAccountInfo , derivedAddresses , nil )
require . NoError ( s . T ( ) , err )
2023-01-12 03:00:24 +00:00
account . Name = settings . Name
2023-02-17 13:02:42 +00:00
nodeConfig , err := defaultNodeConfig ( settings . InstallationID , account . KeyUID )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
walletDerivedAccount := derivedAddresses [ pathDefaultWallet ]
walletAccount := & accounts . Account {
PublicKey : types . Hex2Bytes ( walletDerivedAccount . PublicKey ) ,
KeyUID : generatedAccountInfo . KeyUID ,
Address : types . HexToAddress ( walletDerivedAccount . Address ) ,
2023-06-02 15:06:51 +00:00
ColorID : "" ,
2023-01-06 12:21:14 +00:00
Wallet : true ,
Path : pathDefaultWallet ,
Name : "Ethereum account" ,
}
chatDerivedAccount := derivedAddresses [ pathDefaultChat ]
chatAccount := & accounts . Account {
PublicKey : types . Hex2Bytes ( chatDerivedAccount . PublicKey ) ,
KeyUID : generatedAccountInfo . KeyUID ,
Address : types . HexToAddress ( chatDerivedAccount . Address ) ,
Name : settings . Name ,
Chat : true ,
Path : pathDefaultChat ,
}
accounts := [ ] * accounts . Account { walletAccount , chatAccount }
err = backend . StartNodeWithAccountAndInitialConfig ( account , s . password , * settings , nodeConfig , accounts )
require . NoError ( s . T ( ) , err )
2023-05-18 06:27:16 +00:00
multiaccounts , err := backend . GetAccounts ( )
require . NoError ( s . T ( ) , err )
require . NotEmpty ( s . T ( ) , multiaccounts [ 0 ] . ColorHash )
2023-02-28 12:32:45 +00:00
2023-01-06 12:21:14 +00:00
return backend
}
func ( s * SyncDeviceSuite ) prepareBackendWithoutAccount ( tmpdir string ) * api . GethStatusBackend {
backend := api . NewGethStatusBackend ( )
backend . UpdateRootDataDir ( tmpdir )
return backend
}
2023-07-12 09:46:56 +00:00
func ( s * SyncDeviceSuite ) pairAccounts ( serverBackend * api . GethStatusBackend , serverDir string ,
clientBackend * api . GethStatusBackend , clientDir string ) {
// Start sender server
serverActiveAccount , err := serverBackend . GetActiveAccount ( )
require . NoError ( s . T ( ) , err )
serverKeystorePath := filepath . Join ( serverDir , keystoreDir , serverActiveAccount . KeyUID )
serverConfig := & SenderServerConfig {
SenderConfig : & SenderConfig {
KeystorePath : serverKeystorePath ,
DeviceType : "desktop" ,
KeyUID : serverActiveAccount . KeyUID ,
Password : s . password ,
} ,
ServerConfig : new ( ServerConfig ) ,
}
configBytes , err := json . Marshal ( serverConfig )
require . NoError ( s . T ( ) , err )
connectionString , err := StartUpSenderServer ( serverBackend , string ( configBytes ) )
require . NoError ( s . T ( ) , err )
// Start receiving client
err = clientBackend . AccountManager ( ) . InitKeystore ( filepath . Join ( clientDir , keystoreDir ) )
require . NoError ( s . T ( ) , err )
err = clientBackend . OpenAccounts ( )
require . NoError ( s . T ( ) , err )
clientNodeConfig , err := defaultNodeConfig ( uuid . New ( ) . String ( ) , "" )
require . NoError ( s . T ( ) , err )
expectedKDFIterations := 2048
clientKeystoreDir := filepath . Join ( clientDir , keystoreDir )
clientPayloadSourceConfig := ReceiverClientConfig {
ReceiverConfig : & ReceiverConfig {
KeystorePath : clientKeystoreDir ,
DeviceType : "desktop" ,
KDFIterations : expectedKDFIterations ,
NodeConfig : clientNodeConfig ,
SettingCurrentNetwork : currentNetwork ,
} ,
ClientConfig : new ( ClientConfig ) ,
}
clientNodeConfig . RootDataDir = clientDir
clientConfigBytes , err := json . Marshal ( clientPayloadSourceConfig )
require . NoError ( s . T ( ) , err )
err = StartUpReceivingClient ( clientBackend , connectionString , string ( clientConfigBytes ) )
require . NoError ( s . T ( ) , err )
require . True ( s . T ( ) , serverBackend . Messenger ( ) . HasPairedDevices ( ) )
require . True ( s . T ( ) , clientBackend . Messenger ( ) . HasPairedDevices ( ) )
}
func ( s * SyncDeviceSuite ) sendContactRequest ( request * requests . SendContactRequest , messenger * protocol . Messenger ) {
senderPublicKey := common . PubkeyToHex ( messenger . IdentityPublicKey ( ) )
s . logger . Info ( "sendContactRequest" , zap . String ( "sender" , senderPublicKey ) , zap . String ( "receiver" , request . ID ) )
resp , err := messenger . SendContactRequest ( context . Background ( ) , request )
s . Require ( ) . NoError ( err )
s . Require ( ) . NotNil ( resp )
}
func ( s * SyncDeviceSuite ) receiveContactRequest ( messageText string , messenger * protocol . Messenger ) * common . Message {
receiverPublicKey := types . EncodeHex ( crypto . FromECDSAPub ( messenger . IdentityPublicKey ( ) ) )
s . logger . Info ( "receiveContactRequest" , zap . String ( "receiver" , receiverPublicKey ) )
// Wait for the message to reach its destination
resp , err := protocol . WaitOnMessengerResponse (
messenger ,
func ( r * protocol . MessengerResponse ) bool {
return len ( r . Contacts ) == 1 && len ( r . Messages ( ) ) == 2 && len ( r . ActivityCenterNotifications ( ) ) == 1
} ,
"no messages" ,
)
s . Require ( ) . NoError ( err )
s . Require ( ) . NotNil ( resp )
contactRequest := protocol . FindFirstByContentType ( resp . Messages ( ) , protobuf . ChatMessage_CONTACT_REQUEST )
s . Require ( ) . NotNil ( contactRequest )
return contactRequest
}
func ( s * SyncDeviceSuite ) acceptContactRequest ( contactRequest * common . Message , sender * protocol . Messenger , receiver * protocol . Messenger ) {
senderPublicKey := types . EncodeHex ( crypto . FromECDSAPub ( sender . IdentityPublicKey ( ) ) )
receiverPublicKey := types . EncodeHex ( crypto . FromECDSAPub ( receiver . IdentityPublicKey ( ) ) )
s . logger . Info ( "acceptContactRequest" , zap . String ( "sender" , senderPublicKey ) , zap . String ( "receiver" , receiverPublicKey ) )
_ , err := receiver . AcceptContactRequest ( context . Background ( ) , & requests . AcceptContactRequest { ID : types . Hex2Bytes ( contactRequest . ID ) } )
s . Require ( ) . NoError ( err )
// Wait for the message to reach its destination
resp , err := protocol . WaitOnMessengerResponse (
sender ,
func ( r * protocol . MessengerResponse ) bool {
return len ( r . Contacts ) == 1 && len ( r . Messages ( ) ) == 2 && len ( r . ActivityCenterNotifications ( ) ) == 1
} ,
"no messages" ,
)
s . Require ( ) . NoError ( err )
s . Require ( ) . NotNil ( resp )
}
func ( s * SyncDeviceSuite ) checkMutualContact ( backend * api . GethStatusBackend , contactPublicKey string ) {
messenger := backend . Messenger ( )
contacts := messenger . MutualContacts ( )
s . Require ( ) . Len ( contacts , 1 )
contact := contacts [ 0 ]
s . Require ( ) . Equal ( contactPublicKey , contact . ID )
s . Require ( ) . Equal ( protocol . ContactRequestStateSent , contact . ContactRequestLocalState )
s . Require ( ) . Equal ( protocol . ContactRequestStateReceived , contact . ContactRequestRemoteState )
s . Require ( ) . NotNil ( contact . DisplayName )
}
2023-01-06 12:21:14 +00:00
func ( s * SyncDeviceSuite ) TestPairingSyncDeviceClientAsSender ( ) {
clientTmpDir := filepath . Join ( s . clientAsSenderTmpdir , "client" )
clientBackend := s . prepareBackendWithAccount ( clientTmpDir )
serverTmpDir := filepath . Join ( s . clientAsSenderTmpdir , "server" )
serverBackend := s . prepareBackendWithoutAccount ( serverTmpDir )
defer func ( ) {
require . NoError ( s . T ( ) , serverBackend . Logout ( ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , clientBackend . Logout ( ) )
2023-01-06 12:21:14 +00:00
} ( )
2023-05-12 08:31:34 +00:00
ctx := context . TODO ( )
2023-01-06 12:21:14 +00:00
err := serverBackend . AccountManager ( ) . InitKeystore ( filepath . Join ( serverTmpDir , keystoreDir ) )
require . NoError ( s . T ( ) , err )
err = serverBackend . OpenAccounts ( )
require . NoError ( s . T ( ) , err )
2023-02-17 13:02:42 +00:00
serverNodeConfig , err := defaultNodeConfig ( uuid . New ( ) . String ( ) , "" )
require . NoError ( s . T ( ) , err )
expectedKDFIterations := 1024
serverKeystoreDir := filepath . Join ( serverTmpDir , keystoreDir )
2023-03-23 11:44:15 +00:00
serverPayloadSourceConfig := & ReceiverServerConfig {
ReceiverConfig : & ReceiverConfig {
2023-02-17 13:02:42 +00:00
NodeConfig : serverNodeConfig ,
2023-03-23 11:44:15 +00:00
KeystorePath : serverKeystoreDir ,
DeviceType : "desktop" ,
KDFIterations : expectedKDFIterations ,
2023-02-17 13:02:42 +00:00
SettingCurrentNetwork : currentNetwork ,
} ,
2023-03-23 11:44:15 +00:00
ServerConfig : new ( ServerConfig ) ,
2023-02-17 13:02:42 +00:00
}
2023-03-23 11:44:15 +00:00
serverNodeConfig . RootDataDir = serverTmpDir
2023-02-17 13:02:42 +00:00
serverConfigBytes , err := json . Marshal ( serverPayloadSourceConfig )
require . NoError ( s . T ( ) , err )
2023-03-21 13:08:28 +00:00
cs , err := StartUpReceiverServer ( serverBackend , string ( serverConfigBytes ) )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
// generate some data for the client
2023-05-12 08:31:34 +00:00
// generate bookmark
2023-01-06 12:21:14 +00:00
clientBrowserAPI := clientBackend . StatusNode ( ) . BrowserService ( ) . APIs ( ) [ 0 ] . Service . ( * browsers . API )
2023-05-12 08:31:34 +00:00
_ , err = clientBrowserAPI . StoreBookmark ( ctx , browsers . Bookmark {
2023-01-06 12:21:14 +00:00
Name : "status.im" ,
URL : "https://status.im" ,
} )
require . NoError ( s . T ( ) , err )
2023-05-12 08:31:34 +00:00
// generate social link
2023-06-05 11:10:26 +00:00
socialLinksToAdd := identity . SocialLinks { { Text : identity . GithubID , URL : socialLinkURL } }
err = clientBackend . Messenger ( ) . AddOrReplaceSocialLinks ( socialLinksToAdd )
2023-04-19 22:59:09 +00:00
require . NoError ( s . T ( ) , err )
2023-05-12 08:31:34 +00:00
// generate ens username
err = clientBackend . StatusNode ( ) . EnsService ( ) . API ( ) . Add ( ctx , ensChainID , ensUsername )
2023-04-26 15:37:18 +00:00
require . NoError ( s . T ( ) , err )
2023-01-12 03:00:24 +00:00
clientActiveAccount , err := clientBackend . GetActiveAccount ( )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
2023-01-12 03:00:24 +00:00
clientKeystorePath := filepath . Join ( clientTmpDir , keystoreDir , clientActiveAccount . KeyUID )
2023-03-23 11:44:15 +00:00
clientPayloadSourceConfig := SenderClientConfig {
SenderConfig : & SenderConfig {
KeystorePath : clientKeystorePath ,
DeviceType : "android" ,
KeyUID : clientActiveAccount . KeyUID ,
Password : s . password ,
2023-02-17 13:02:42 +00:00
} ,
2023-03-23 11:44:15 +00:00
ClientConfig : new ( ClientConfig ) ,
2023-01-06 12:21:14 +00:00
}
2023-02-17 13:02:42 +00:00
clientConfigBytes , err := json . Marshal ( clientPayloadSourceConfig )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
2023-03-23 11:44:15 +00:00
err = StartUpSendingClient ( clientBackend , cs , string ( clientConfigBytes ) )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
2023-04-19 22:59:09 +00:00
// check that the server has the same data as the client
2023-01-06 12:21:14 +00:00
serverBrowserAPI := serverBackend . StatusNode ( ) . BrowserService ( ) . APIs ( ) [ 0 ] . Service . ( * browsers . API )
2023-05-12 08:31:34 +00:00
bookmarks , err := serverBrowserAPI . GetBookmarks ( ctx )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
require . Equal ( s . T ( ) , 1 , len ( bookmarks ) )
require . Equal ( s . T ( ) , "status.im" , bookmarks [ 0 ] . Name )
2023-06-05 11:10:26 +00:00
serverSocialLinks , err := serverBackend . Messenger ( ) . GetSocialLinks ( )
2023-04-19 22:59:09 +00:00
require . NoError ( s . T ( ) , err )
2023-06-05 11:10:26 +00:00
require . Equal ( s . T ( ) , 1 , len ( serverSocialLinks ) )
require . True ( s . T ( ) , socialLinksToAdd . Equal ( serverSocialLinks ) )
2023-05-12 08:31:34 +00:00
uds , err := serverBackend . StatusNode ( ) . EnsService ( ) . API ( ) . GetEnsUsernames ( ctx )
2023-04-26 15:37:18 +00:00
require . NoError ( s . T ( ) , err )
require . Equal ( s . T ( ) , 1 , len ( uds ) )
require . Equal ( s . T ( ) , ensUsername , uds [ 0 ] . Username )
require . Equal ( s . T ( ) , uint64 ( ensChainID ) , uds [ 0 ] . ChainID )
require . False ( s . T ( ) , uds [ 0 ] . Removed )
require . Greater ( s . T ( ) , uds [ 0 ] . Clock , uint64 ( 0 ) )
2023-01-12 03:00:24 +00:00
serverActiveAccount , err := serverBackend . GetActiveAccount ( )
require . NoError ( s . T ( ) , err )
require . Equal ( s . T ( ) , serverActiveAccount . Name , clientActiveAccount . Name )
2023-02-17 13:02:42 +00:00
require . Equal ( s . T ( ) , serverActiveAccount . KDFIterations , expectedKDFIterations )
2023-02-28 12:32:45 +00:00
serverMessenger := serverBackend . Messenger ( )
clientMessenger := clientBackend . Messenger ( )
require . True ( s . T ( ) , serverMessenger . HasPairedDevices ( ) )
require . True ( s . T ( ) , clientMessenger . HasPairedDevices ( ) )
err = clientMessenger . DisableInstallation ( serverNodeConfig . ShhextConfig . InstallationID )
require . NoError ( s . T ( ) , err )
require . False ( s . T ( ) , clientMessenger . HasPairedDevices ( ) )
clientNodeConfig , err := clientBackend . GetNodeConfig ( )
require . NoError ( s . T ( ) , err )
err = serverMessenger . DisableInstallation ( clientNodeConfig . ShhextConfig . InstallationID )
require . NoError ( s . T ( ) , err )
require . False ( s . T ( ) , serverMessenger . HasPairedDevices ( ) )
// repeat local pairing, we should expect no error after receiver logged in
2023-03-21 13:08:28 +00:00
cs , err = StartUpReceiverServer ( serverBackend , string ( serverConfigBytes ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , err )
2023-03-23 11:44:15 +00:00
err = StartUpSendingClient ( clientBackend , cs , string ( clientConfigBytes ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , err )
require . True ( s . T ( ) , clientMessenger . HasPairedDevices ( ) )
require . True ( s . T ( ) , serverMessenger . HasPairedDevices ( ) )
// test if it's okay when account already exist but not logged in
require . NoError ( s . T ( ) , serverBackend . Logout ( ) )
2023-03-21 13:08:28 +00:00
cs , err = StartUpReceiverServer ( serverBackend , string ( serverConfigBytes ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , err )
2023-03-23 11:44:15 +00:00
err = StartUpSendingClient ( clientBackend , cs , string ( clientConfigBytes ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , err )
2023-01-06 12:21:14 +00:00
}
func ( s * SyncDeviceSuite ) TestPairingSyncDeviceClientAsReceiver ( ) {
clientTmpDir := filepath . Join ( s . clientAsReceiverTmpdir , "client" )
clientBackend := s . prepareBackendWithoutAccount ( clientTmpDir )
2023-05-12 08:31:34 +00:00
ctx := context . TODO ( )
2023-01-06 12:21:14 +00:00
serverTmpDir := filepath . Join ( s . clientAsReceiverTmpdir , "server" )
serverBackend := s . prepareBackendWithAccount ( serverTmpDir )
defer func ( ) {
require . NoError ( s . T ( ) , clientBackend . Logout ( ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , serverBackend . Logout ( ) )
2023-01-06 12:21:14 +00:00
} ( )
2023-01-12 03:00:24 +00:00
serverActiveAccount , err := serverBackend . GetActiveAccount ( )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
2023-01-12 03:00:24 +00:00
serverKeystorePath := filepath . Join ( serverTmpDir , keystoreDir , serverActiveAccount . KeyUID )
2023-03-23 11:44:15 +00:00
var config = & SenderServerConfig {
SenderConfig : & SenderConfig {
KeystorePath : serverKeystorePath ,
DeviceType : "desktop" ,
KeyUID : serverActiveAccount . KeyUID ,
Password : s . password ,
2023-02-17 13:02:42 +00:00
} ,
2023-03-23 11:44:15 +00:00
ServerConfig : new ( ServerConfig ) ,
2023-01-06 12:21:14 +00:00
}
configBytes , err := json . Marshal ( config )
require . NoError ( s . T ( ) , err )
2023-03-21 13:08:28 +00:00
cs , err := StartUpSenderServer ( serverBackend , string ( configBytes ) )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
// generate some data for the server
2023-05-12 08:31:34 +00:00
// generate bookmark
2023-01-06 12:21:14 +00:00
serverBrowserAPI := serverBackend . StatusNode ( ) . BrowserService ( ) . APIs ( ) [ 0 ] . Service . ( * browsers . API )
2023-05-12 08:31:34 +00:00
_ , err = serverBrowserAPI . StoreBookmark ( ctx , browsers . Bookmark {
2023-01-06 12:21:14 +00:00
Name : "status.im" ,
URL : "https://status.im" ,
} )
require . NoError ( s . T ( ) , err )
2023-05-12 08:31:34 +00:00
// generate social link
serverMessenger := serverBackend . Messenger ( )
2023-06-05 11:10:26 +00:00
socialLinksToAdd := identity . SocialLinks { { Text : identity . GithubID , URL : socialLinkURL } }
err = serverMessenger . AddOrReplaceSocialLinks ( socialLinksToAdd )
2023-04-19 22:59:09 +00:00
require . NoError ( s . T ( ) , err )
2023-05-12 08:31:34 +00:00
// generate ens username
err = serverBackend . StatusNode ( ) . EnsService ( ) . API ( ) . Add ( ctx , ensChainID , ensUsername )
require . NoError ( s . T ( ) , err )
// generate local deleted message
_ , err = serverMessenger . CreatePublicChat ( & requests . CreatePublicChat { ID : publicChatID } )
require . NoError ( s . T ( ) , err )
serverChat := serverMessenger . Chat ( publicChatID )
serverMessage := buildTestMessage ( serverChat )
serverMessengerResponse , err := serverMessenger . SendChatMessage ( ctx , serverMessage )
require . NoError ( s . T ( ) , err )
require . Equal ( s . T ( ) , 1 , len ( serverMessengerResponse . Messages ( ) ) )
serverMessageID := serverMessengerResponse . Messages ( ) [ 0 ] . ID
_ , err = serverMessenger . DeleteMessageForMeAndSync ( ctx , publicChatID , serverMessageID )
2023-04-26 15:37:18 +00:00
require . NoError ( s . T ( ) , err )
2023-01-06 12:21:14 +00:00
err = clientBackend . AccountManager ( ) . InitKeystore ( filepath . Join ( clientTmpDir , keystoreDir ) )
require . NoError ( s . T ( ) , err )
err = clientBackend . OpenAccounts ( )
require . NoError ( s . T ( ) , err )
2023-02-17 13:02:42 +00:00
clientNodeConfig , err := defaultNodeConfig ( uuid . New ( ) . String ( ) , "" )
require . NoError ( s . T ( ) , err )
expectedKDFIterations := 2048
clientKeystoreDir := filepath . Join ( clientTmpDir , keystoreDir )
2023-03-23 11:44:15 +00:00
clientPayloadSourceConfig := ReceiverClientConfig {
ReceiverConfig : & ReceiverConfig {
KeystorePath : clientKeystoreDir ,
DeviceType : "iphone" ,
2023-02-17 13:02:42 +00:00
KDFIterations : expectedKDFIterations ,
NodeConfig : clientNodeConfig ,
SettingCurrentNetwork : currentNetwork ,
} ,
2023-03-23 11:44:15 +00:00
ClientConfig : new ( ClientConfig ) ,
2023-02-17 13:02:42 +00:00
}
2023-03-23 11:44:15 +00:00
clientNodeConfig . RootDataDir = clientTmpDir
2023-02-17 13:02:42 +00:00
clientConfigBytes , err := json . Marshal ( clientPayloadSourceConfig )
require . NoError ( s . T ( ) , err )
2023-03-23 11:44:15 +00:00
err = StartUpReceivingClient ( clientBackend , cs , string ( clientConfigBytes ) )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
2023-04-19 22:59:09 +00:00
// check that the client has the same data as the server
2023-05-12 08:31:34 +00:00
clientMessenger := clientBackend . Messenger ( )
2023-01-06 12:21:14 +00:00
clientBrowserAPI := clientBackend . StatusNode ( ) . BrowserService ( ) . APIs ( ) [ 0 ] . Service . ( * browsers . API )
2023-05-12 08:31:34 +00:00
bookmarks , err := clientBrowserAPI . GetBookmarks ( ctx )
2023-01-06 12:21:14 +00:00
require . NoError ( s . T ( ) , err )
require . Equal ( s . T ( ) , 1 , len ( bookmarks ) )
require . Equal ( s . T ( ) , "status.im" , bookmarks [ 0 ] . Name )
2023-06-05 11:10:26 +00:00
clientSocialLinks , err := clientMessenger . GetSocialLinks ( )
2023-04-19 22:59:09 +00:00
require . NoError ( s . T ( ) , err )
2023-06-05 11:10:26 +00:00
require . Equal ( s . T ( ) , 1 , len ( clientSocialLinks ) )
require . True ( s . T ( ) , socialLinksToAdd . Equal ( clientSocialLinks ) )
2023-05-12 08:31:34 +00:00
uds , err := clientBackend . StatusNode ( ) . EnsService ( ) . API ( ) . GetEnsUsernames ( ctx )
2023-04-26 15:37:18 +00:00
require . NoError ( s . T ( ) , err )
require . Equal ( s . T ( ) , 1 , len ( uds ) )
require . Equal ( s . T ( ) , ensUsername , uds [ 0 ] . Username )
require . Equal ( s . T ( ) , uint64 ( ensChainID ) , uds [ 0 ] . ChainID )
2023-05-12 08:31:34 +00:00
deleteForMeMessages , err := clientMessenger . GetDeleteForMeMessages ( )
require . NoError ( s . T ( ) , err )
require . Equal ( s . T ( ) , 1 , len ( deleteForMeMessages ) )
2023-01-12 03:00:24 +00:00
clientActiveAccount , err := clientBackend . GetActiveAccount ( )
require . NoError ( s . T ( ) , err )
require . Equal ( s . T ( ) , serverActiveAccount . Name , clientActiveAccount . Name )
2023-02-17 13:02:42 +00:00
require . Equal ( s . T ( ) , clientActiveAccount . KDFIterations , expectedKDFIterations )
2023-02-28 12:32:45 +00:00
require . True ( s . T ( ) , serverMessenger . HasPairedDevices ( ) )
require . True ( s . T ( ) , clientMessenger . HasPairedDevices ( ) )
err = serverMessenger . DisableInstallation ( clientNodeConfig . ShhextConfig . InstallationID )
require . NoError ( s . T ( ) , err )
require . False ( s . T ( ) , serverMessenger . HasPairedDevices ( ) )
serverNodeConfig , err := serverBackend . GetNodeConfig ( )
require . NoError ( s . T ( ) , err )
err = clientMessenger . DisableInstallation ( serverNodeConfig . ShhextConfig . InstallationID )
require . NoError ( s . T ( ) , err )
require . False ( s . T ( ) , clientMessenger . HasPairedDevices ( ) )
// repeat local pairing, we should expect no error after receiver logged in
2023-03-21 13:08:28 +00:00
cs , err = StartUpSenderServer ( serverBackend , string ( configBytes ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , err )
2023-03-23 11:44:15 +00:00
err = StartUpReceivingClient ( clientBackend , cs , string ( clientConfigBytes ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , err )
require . True ( s . T ( ) , serverMessenger . HasPairedDevices ( ) )
require . True ( s . T ( ) , clientMessenger . HasPairedDevices ( ) )
// test if it's okay when account already exist but not logged in
require . NoError ( s . T ( ) , clientBackend . Logout ( ) )
2023-03-21 13:08:28 +00:00
cs , err = StartUpSenderServer ( serverBackend , string ( configBytes ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , err )
2023-03-23 11:44:15 +00:00
err = StartUpReceivingClient ( clientBackend , cs , string ( clientConfigBytes ) )
2023-02-28 12:32:45 +00:00
require . NoError ( s . T ( ) , err )
2023-01-06 12:21:14 +00:00
}
2023-07-12 09:46:56 +00:00
func ( s * SyncDeviceSuite ) TestPairingThreeDevices ( ) {
bobTmpDir := filepath . Join ( s . pairThreeDevicesTmpdir , "bob" )
bobBackend := s . prepareBackendWithAccount ( bobTmpDir )
bobMessenger := bobBackend . Messenger ( )
_ , err := bobMessenger . Start ( )
s . Require ( ) . NoError ( err )
alice1TmpDir := filepath . Join ( s . pairThreeDevicesTmpdir , "alice1" )
alice1Backend := s . prepareBackendWithAccount ( alice1TmpDir )
alice1Messenger := alice1Backend . Messenger ( )
_ , err = alice1Messenger . Start ( )
s . Require ( ) . NoError ( err )
alice2TmpDir := filepath . Join ( s . pairThreeDevicesTmpdir , "alice2" )
alice2Backend := s . prepareBackendWithoutAccount ( alice2TmpDir )
alice3TmpDir := filepath . Join ( s . pairThreeDevicesTmpdir , "alice3" )
alice3Backend := s . prepareBackendWithAccount ( alice3TmpDir )
defer func ( ) {
require . NoError ( s . T ( ) , bobBackend . Logout ( ) )
require . NoError ( s . T ( ) , alice1Backend . Logout ( ) )
require . NoError ( s . T ( ) , alice2Backend . Logout ( ) )
require . NoError ( s . T ( ) , alice3Backend . Logout ( ) )
} ( )
// Make Alice and Bob mutual contacts
messageText := "hello!"
bobPublicKey := types . EncodeHex ( crypto . FromECDSAPub ( bobMessenger . IdentityPublicKey ( ) ) )
request := & requests . SendContactRequest {
ID : bobPublicKey ,
Message : messageText ,
}
s . sendContactRequest ( request , alice1Messenger )
contactRequest := s . receiveContactRequest ( messageText , bobMessenger )
s . acceptContactRequest ( contactRequest , alice1Messenger , bobMessenger )
s . checkMutualContact ( alice1Backend , bobPublicKey )
// We shouldn't sync ourselves as a contact, so we check there's only Bob
// https://github.com/status-im/status-go/issues/3667
s . Require ( ) . Equal ( 1 , len ( alice1Backend . Messenger ( ) . Contacts ( ) ) )
// Pair alice-1 <-> alice-2
s . logger . Info ( "pairing Alice-1 and Alice-2" )
s . pairAccounts ( alice1Backend , alice1TmpDir , alice2Backend , alice2TmpDir )
s . checkMutualContact ( alice2Backend , bobPublicKey )
s . Require ( ) . Equal ( 1 , len ( alice2Backend . Messenger ( ) . Contacts ( ) ) )
// Pair Alice-2 <-> ALice-3
s . logger . Info ( "pairing Alice-2 and Alice-3" )
s . pairAccounts ( alice2Backend , alice2TmpDir , alice3Backend , alice3TmpDir )
s . checkMutualContact ( alice3Backend , bobPublicKey )
s . Require ( ) . Equal ( 1 , len ( alice3Backend . Messenger ( ) . Contacts ( ) ) )
}
2023-01-06 12:21:14 +00:00
func defaultSettings ( generatedAccountInfo generator . GeneratedAccountInfo , derivedAddresses map [ string ] generator . AccountInfo , mnemonic * string ) ( * settings . Settings , error ) {
chatKeyString := derivedAddresses [ pathDefaultChat ] . PublicKey
2023-04-02 23:08:29 +00:00
syncSettings := & settings . Settings { }
syncSettings . KeyUID = generatedAccountInfo . KeyUID
syncSettings . Address = types . HexToAddress ( generatedAccountInfo . Address )
syncSettings . WalletRootAddress = types . HexToAddress ( derivedAddresses [ pathWalletRoot ] . Address )
2023-01-06 12:21:14 +00:00
// Set chat key & name
name , err := alias . GenerateFromPublicKeyString ( chatKeyString )
if err != nil {
return nil , err
}
2023-04-02 23:08:29 +00:00
syncSettings . Name = name
syncSettings . PublicKey = chatKeyString
2023-01-06 12:21:14 +00:00
2023-04-02 23:08:29 +00:00
syncSettings . DappsAddress = types . HexToAddress ( derivedAddresses [ pathDefaultWallet ] . Address )
syncSettings . EIP1581Address = types . HexToAddress ( derivedAddresses [ pathEIP1581 ] . Address )
syncSettings . Mnemonic = mnemonic
2023-01-06 12:21:14 +00:00
2023-04-02 23:08:29 +00:00
syncSettings . SigningPhrase = "balabala"
2023-01-06 12:21:14 +00:00
2023-04-02 23:08:29 +00:00
syncSettings . SendPushNotifications = true
syncSettings . InstallationID = uuid . New ( ) . String ( )
syncSettings . UseMailservers = true
2023-01-06 12:21:14 +00:00
2023-04-02 23:08:29 +00:00
syncSettings . PreviewPrivacy = true
syncSettings . Currency = "usd"
syncSettings . ProfilePicturesVisibility = 1
syncSettings . LinkPreviewRequestEnabled = true
2023-01-06 12:21:14 +00:00
visibleTokens := make ( map [ string ] [ ] string )
visibleTokens [ "mainnet" ] = [ ] string { "SNT" }
visibleTokensJSON , err := json . Marshal ( visibleTokens )
if err != nil {
return nil , err
}
visibleTokenJSONRaw := json . RawMessage ( visibleTokensJSON )
2023-04-02 23:08:29 +00:00
syncSettings . WalletVisibleTokens = & visibleTokenJSONRaw
2023-01-06 12:21:14 +00:00
2023-03-29 15:51:01 +00:00
networks := ` [ { "id":"goerli_rpc","chain-explorer-link":"https://goerli.etherscan.io/address/","name":"Goerli with upstream RPC","config": { "NetworkId":5,"DataDir":"/ethereum/goerli_rpc","UpstreamConfig": { "Enabled":true,"URL":"https://goerli-archival.gateway.pokt.network/v1/lb/3ef2018191814b7e1009b8d9"}}}, { "id":"mainnet_rpc","chain-explorer-link":"https://etherscan.io/address/","name":"Mainnet with upstream RPC","config": { "NetworkId":1,"DataDir":"/ethereum/mainnet_rpc","UpstreamConfig": { "Enabled":true,"URL":"https://eth-archival.gateway.pokt.network/v1/lb/3ef2018191814b7e1009b8d9"}}}] `
var networksRawMessage json . RawMessage = [ ] byte ( networks )
2023-04-02 23:08:29 +00:00
syncSettings . Networks = & networksRawMessage
syncSettings . CurrentNetwork = currentNetwork
2023-01-06 12:21:14 +00:00
2023-04-02 23:08:29 +00:00
return syncSettings , nil
2023-01-06 12:21:14 +00:00
}
2023-02-17 13:02:42 +00:00
func defaultNodeConfig ( installationID , keyUID string ) ( * params . NodeConfig , error ) {
2023-01-06 12:21:14 +00:00
// Set mainnet
nodeConfig := & params . NodeConfig { }
nodeConfig . NetworkID = 1
nodeConfig . LogLevel = "ERROR"
2023-02-17 13:02:42 +00:00
nodeConfig . DataDir = filepath . Join ( "ethereum/mainnet_rpc" )
nodeConfig . KeyStoreDir = filepath . Join ( keystoreDir , keyUID )
2023-01-06 12:21:14 +00:00
nodeConfig . UpstreamConfig = params . UpstreamRPCConfig {
Enabled : true ,
URL : "https://mainnet.infura.io/v3/800c641949d64d768a5070a1b0511938" ,
}
nodeConfig . Name = "StatusIM"
clusterConfig , err := params . LoadClusterConfigFromFleet ( "eth.prod" )
if err != nil {
return nil , err
}
nodeConfig . ClusterConfig = * clusterConfig
nodeConfig . WalletConfig = params . WalletConfig { Enabled : false }
nodeConfig . LocalNotificationsConfig = params . LocalNotificationsConfig { Enabled : true }
nodeConfig . BrowsersConfig = params . BrowsersConfig { Enabled : false }
nodeConfig . PermissionsConfig = params . PermissionsConfig { Enabled : true }
nodeConfig . MailserversConfig = params . MailserversConfig { Enabled : true }
nodeConfig . EnableNTPSync = true
nodeConfig . WakuConfig = params . WakuConfig {
Enabled : true ,
LightClient : true ,
MinimumPoW : 0.000001 ,
}
nodeConfig . ShhextConfig = params . ShhextConfig {
2023-03-29 15:51:01 +00:00
BackupDisabledDataDir : nodeConfig . DataDir ,
2023-01-06 12:21:14 +00:00
InstallationID : installationID ,
MaxMessageDeliveryAttempts : 6 ,
MailServerConfirmations : true ,
VerifyTransactionURL : "" ,
VerifyENSURL : "" ,
VerifyENSContractAddress : "" ,
VerifyTransactionChainID : 1 ,
DataSyncEnabled : true ,
PFSEnabled : true ,
}
return nodeConfig , nil
}
2023-05-12 08:31:34 +00:00
type testTimeSource struct { }
func ( t * testTimeSource ) GetCurrentTime ( ) uint64 {
return uint64 ( time . Now ( ) . Unix ( ) )
}
func buildTestMessage ( chat * protocol . Chat ) * common . Message {
clock , timestamp := chat . NextClockAndTimestamp ( & testTimeSource { } )
message := & common . Message { }
message . Text = "text-input-message"
message . ChatId = chat . ID
message . Clock = clock
message . Timestamp = timestamp
message . WhisperTimestamp = clock
message . LocalChatID = chat . ID
message . ContentType = protobuf . ChatMessage_TEXT_PLAIN
switch chat . ChatType {
case protocol . ChatTypePublic , protocol . ChatTypeProfile :
message . MessageType = protobuf . MessageType_PUBLIC_GROUP
case protocol . ChatTypeOneToOne :
message . MessageType = protobuf . MessageType_ONE_TO_ONE
case protocol . ChatTypePrivateGroupChat :
message . MessageType = protobuf . MessageType_PRIVATE_GROUP
}
return message
}