Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/fallback pairing seed2 #5614

Merged
merged 11 commits into from
Jul 30, 2024
104 changes: 104 additions & 0 deletions api/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"database/sql"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math/rand"
Expand All @@ -17,6 +18,8 @@ import (
"testing"
"time"

"github.com/status-im/status-go/protocol/tt"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -880,6 +883,107 @@ func TestLoginAccount(t *testing.T) {
require.Equal(t, nameserver, b.config.WakuV2Config.Nameserver)
}

func TestEnableInstallationAndPair(t *testing.T) {
// create account acc
utils.Init()
displayName := "some-display-name"
password := "some-password"
tmpdir := t.TempDir()
nameserver := "8.8.8.8"
b := NewGethStatusBackend()
createAccountRequest := &requests.CreateAccount{
DisplayName: displayName,
CustomizationColor: "#ffffff",
Emoji: "some",
Password: password,
RootDataDir: tmpdir,
LogFilePath: tmpdir + "/log",
WakuV2Nameserver: &nameserver,
WakuV2Fleet: "status.staging",
}
acc, err := b.CreateAccountAndLogin(createAccountRequest)
require.NoError(t, err)
require.NotNil(t, acc)
_, err = b.Messenger().Start()
require.NoError(t, err)
s, err := b.GetSettings()
require.NoError(t, err)
mn := *s.Mnemonic
db, err := accounts.NewDB(b.appDB)
require.NoError(t, err)
n, err := db.GetSettingLastSynced(settings.DisplayName)
require.NoError(t, err)
require.True(t, n > 0)

// restore account acc as acc2 use Mnemonic from acc
restoreRequest := &requests.RestoreAccount{
Mnemonic: mn,
FetchBackup: true,
CreateAccount: requests.CreateAccount{
Password: password,
CustomizationColor: "0x000000",
RootDataDir: t.TempDir(),
},
}
b2 := NewGethStatusBackend()
acc2, err := b2.RestoreAccountAndLogin(restoreRequest)
require.NoError(t, err)
require.NotNil(t, acc2)
_, err = b2.Messenger().Start()
require.NoError(t, err)
s2, err := b2.GetSettings()
require.NoError(t, err)

t.Logf("acc2 settings.name: %s", s2.Name)
// should be 3 words random name
require.Len(t, strings.Split(s2.Name, " "), 3)
require.Empty(t, acc2.Name)
require.Empty(t, s2.DisplayName)
db2, err := accounts.NewDB(b2.appDB)
require.NoError(t, err)
n, err = db2.GetSettingLastSynced(settings.DisplayName)
require.NoError(t, err)
require.True(t, n == 0)

// pair installation
_, err = b2.Messenger().EnableInstallationAndPair(&requests.EnableInstallationAndPair{InstallationID: s.InstallationID})
require.NoError(t, err)
// ensure acc received the installation from acc2
err = tt.RetryWithBackOff(func() error {
r, err := b.Messenger().RetrieveAll()
require.NoError(t, err)
if len(r.Installations()) > 0 {
return nil
}
return errors.New("new installation not received yet")
})
require.NoError(t, err)

// sync data from acc to acc2
err = b.Messenger().EnableAndSyncInstallation(&requests.EnableAndSyncInstallation{InstallationID: s2.InstallationID})
require.NoError(t, err)
// ensure acc2's display name get synced
err = tt.RetryWithBackOff(func() error {
r, err := b2.Messenger().RetrieveAll()
require.NoError(t, err)
for _, ss := range r.Settings {
if ss.GetDBName() == "display_name" {
return nil
}
}
return errors.New("display name setting not received yet")
})
require.NoError(t, err)

// check display name for acc2
s2, err = b2.GetSettings()
require.NoError(t, err)
require.Equal(t, displayName, s2.DisplayName)
acc2, err = b2.GetActiveAccount()
require.NoError(t, err)
require.Equal(t, displayName, acc2.Name)
}

func TestVerifyDatabasePassword(t *testing.T) {
utils.Init()

Expand Down
22 changes: 18 additions & 4 deletions api/geth_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,12 @@ var _ StatusBackend = (*GethStatusBackend)(nil)
type GethStatusBackend struct {
mu sync.Mutex
// rootDataDir is the same for all networks.
rootDataDir string
appDB *sql.DB
walletDB *sql.DB
config *params.NodeConfig
rootDataDir string
appDB *sql.DB
walletDB *sql.DB
config *params.NodeConfig
installationID string
keyUID string
qfrank marked this conversation as resolved.
Show resolved Hide resolved

statusNode *node.StatusNode
personalAPI *personal.PublicAPI
Expand Down Expand Up @@ -2658,11 +2660,23 @@ func (b *GethStatusBackend) injectAccountsIntoWakuService(w types.WakuKeyManager
b.statusNode.ChatService(accDB).Init(messenger)
b.statusNode.EnsService().Init(messenger.SyncEnsNamesWithDispatchMessage)
b.statusNode.CommunityTokensService().Init(messenger)
if messenger != nil {
b.installationID = messenger.InstallationID()
b.keyUID = messenger.KeyUID()
}
}

return nil
}

func (b *GethStatusBackend) InstallationID() string {
return b.installationID
}

func (b *GethStatusBackend) KeyUID() string {
return b.keyUID
}

func (b *GethStatusBackend) injectAccountsIntoServices() error {
if b.statusNode.WakuService() != nil {
return b.injectAccountsIntoWakuService(b.statusNode.WakuService(), func() *ext.Service {
Expand Down
30 changes: 27 additions & 3 deletions mobile/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,18 @@ func GetConnectionStringForBootstrappingAnotherDevice(configJSON string) string
return cs
}

type inputConnectionStringForBootstrappingResponse struct {
InstallationID string `json:"installationId"`
KeyUID string `json:"keyUID"`
Error error `json:"error"`
}

func (i *inputConnectionStringForBootstrappingResponse) toJSON(err error) string {
i.Error = err
j, _ := json.Marshal(i)
return string(j)
}

// InputConnectionStringForBootstrapping starts a pairing.ReceiverClient
// The given server.ConnectionParams string will determine the server.Mode
//
Expand All @@ -1202,18 +1214,30 @@ func InputConnectionStringForBootstrapping(cs, configJSON string) string {
return makeJSONResponse(fmt.Errorf("no config given, ReceiverClientConfig is expected"))
}

params := &pairing.ConnectionParams{}
err = params.FromString(cs)
if err != nil {
response := &inputConnectionStringForBootstrappingResponse{}
return response.toJSON(fmt.Errorf("could not parse connection string"))
}
response := &inputConnectionStringForBootstrappingResponse{
InstallationID: params.InstallationID(),
KeyUID: params.KeyUID(),
}

err = statusBackend.LocalPairingStateManager.StartPairing(cs)
defer func() { statusBackend.LocalPairingStateManager.StopPairing(cs, err) }()
if err != nil {
return makeJSONResponse(err)
return response.toJSON(err)
}

err = pairing.StartUpReceivingClient(statusBackend, cs, configJSON)
if err != nil {
return makeJSONResponse(err)
return response.toJSON(err)

}

return makeJSONResponse(statusBackend.Logout())
return response.toJSON(statusBackend.Logout())
}

// InputConnectionStringForBootstrappingAnotherDevice starts a pairing.SendingClient
Expand Down
4 changes: 4 additions & 0 deletions protocol/encryption/multidevice/multidevice.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ type Installation struct {
InstallationMetadata *InstallationMetadata `json:"metadata"`
}

func (i *Installation) UniqueKey() string {
return i.ID + i.Identity
}

type Config struct {
MaxInstallations int
ProtocolVersion uint32
Expand Down
4 changes: 4 additions & 0 deletions protocol/encryption/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ func (p *Protocol) ProcessPublicBundle(myIdentityKey *ecdsa.PrivateKey, bundle *
return p.multidevice.AddInstallations(bundle.GetIdentity(), bundle.GetTimestamp(), installations, enabled)
}

func (p *Protocol) AddInstallation(identity []byte, timestamp int64, installation *multidevice.Installation, enabled bool) ([]*multidevice.Installation, error) {
return p.multidevice.AddInstallations(identity, timestamp, []*multidevice.Installation{installation}, enabled)
}

func (p *Protocol) GetMultiDevice() *multidevice.Multidevice {
return p.multidevice
}
Expand Down
Loading