feat(sync)!: leftovers work for sync fallback (#5794)
* feat(sync)!: remove compatibility with v2.29 * feat(sync)_: add AC notifications when initiating the sync fallback Needed for https://github.com/status-im/status-desktop/issues/15750 Adds an AC notification when the syncing fails and the user is prompted to use a seed phrase instead. There is one notification for the initiator (created) and one for the old account (received). Once the flow is completed, ie the receiver presses Enable and sync, the notifications are deleted * test_: update test * fix_: lint issue * chore_: ignore tmp file generated by make lint-fix * chore_: rename EnableAndSyncInstallation to EnableInstallationAndSync * chore_: address review feedback * chore_: revert changes to .gitignore * fix_: simplify code * fix_: keep old API --------- Co-authored-by: Jonathan Rainville <rainville.jonathan@gmail.com>
This commit is contained in:
parent
6e5a32c022
commit
f04a9a8726
|
@ -40,6 +40,8 @@ const (
|
|||
ActivityCenterNotificationTypeFirstCommunityTokenReceived
|
||||
ActivityCenterNotificationTypeCommunityBanned
|
||||
ActivityCenterNotificationTypeCommunityUnbanned
|
||||
ActivityCenterNotificationTypeNewInstallationReceived
|
||||
ActivityCenterNotificationTypeNewInstallationCreated
|
||||
)
|
||||
|
||||
type ActivityCenterMembershipStatus int
|
||||
|
@ -87,6 +89,7 @@ type ActivityCenterNotification struct {
|
|||
MembershipStatus ActivityCenterMembershipStatus `json:"membershipStatus"`
|
||||
Name string `json:"name"`
|
||||
Author string `json:"author"`
|
||||
InstallationID string `json:"installationId"`
|
||||
Type ActivityCenterType `json:"type"`
|
||||
LastMessage *common.Message `json:"lastMessage"`
|
||||
Message *common.Message `json:"message"`
|
||||
|
|
|
@ -148,9 +148,10 @@ func (db sqlitePersistence) SaveActivityCenterNotification(notification *Activit
|
|||
dismissed,
|
||||
token_data,
|
||||
deleted,
|
||||
updated_at
|
||||
updated_at,
|
||||
installation_id
|
||||
)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
`,
|
||||
notification.ID,
|
||||
notification.Timestamp,
|
||||
|
@ -168,6 +169,7 @@ func (db sqlitePersistence) SaveActivityCenterNotification(notification *Activit
|
|||
encodedTokenData,
|
||||
notification.Deleted,
|
||||
notification.UpdatedAt,
|
||||
notification.InstallationID,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -269,6 +271,7 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRow(row *sql.Row)
|
|||
var tokenDataBytes []byte
|
||||
var name sql.NullString
|
||||
var author sql.NullString
|
||||
var installationID sql.NullString
|
||||
notification := &ActivityCenterNotification{}
|
||||
err := row.Scan(
|
||||
¬ification.ID,
|
||||
|
@ -288,7 +291,9 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRow(row *sql.Row)
|
|||
&name,
|
||||
&author,
|
||||
&tokenDataBytes,
|
||||
¬ification.UpdatedAt)
|
||||
¬ification.UpdatedAt,
|
||||
&installationID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -310,6 +315,10 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRow(row *sql.Row)
|
|||
notification.Author = author.String
|
||||
}
|
||||
|
||||
if installationID.Valid {
|
||||
notification.InstallationID = installationID.String
|
||||
}
|
||||
|
||||
if len(tokenDataBytes) > 0 {
|
||||
err = json.Unmarshal(tokenDataBytes, ¬ification.TokenData)
|
||||
if err != nil {
|
||||
|
@ -359,6 +368,7 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRows(rows *sql.Ro
|
|||
var tokenDataBytes []byte
|
||||
var name sql.NullString
|
||||
var author sql.NullString
|
||||
var installationID sql.NullString
|
||||
notification := &ActivityCenterNotification{}
|
||||
err := rows.Scan(
|
||||
¬ification.ID,
|
||||
|
@ -378,7 +388,9 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRows(rows *sql.Ro
|
|||
&author,
|
||||
&tokenDataBytes,
|
||||
&latestCursor,
|
||||
¬ification.UpdatedAt)
|
||||
¬ification.UpdatedAt,
|
||||
&installationID,
|
||||
)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -399,6 +411,10 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRows(rows *sql.Ro
|
|||
notification.Author = author.String
|
||||
}
|
||||
|
||||
if installationID.Valid {
|
||||
notification.InstallationID = installationID.String
|
||||
}
|
||||
|
||||
if len(tokenDataBytes) > 0 {
|
||||
tokenData := &ActivityTokenData{}
|
||||
if err = json.Unmarshal(tokenDataBytes, &tokenData); err != nil {
|
||||
|
@ -539,7 +555,8 @@ func (db sqlitePersistence) buildActivityCenterQuery(tx *sql.Tx, params activity
|
|||
a.author,
|
||||
a.token_data,
|
||||
substr('0000000000000000000000000000000000000000000000000000000000000000' || a.timestamp, -64, 64) || hex(a.id) as cursor,
|
||||
a.updated_at
|
||||
a.updated_at,
|
||||
a.installation_id
|
||||
FROM activity_center_notifications a
|
||||
LEFT JOIN chats c
|
||||
ON
|
||||
|
@ -660,7 +677,8 @@ func (db sqlitePersistence) GetActivityCenterNotificationsByID(ids []types.HexBy
|
|||
a.author,
|
||||
a.token_data,
|
||||
substr('0000000000000000000000000000000000000000000000000000000000000000' || a.timestamp, -64, 64) || hex(a.id) as cursor,
|
||||
a.updated_at
|
||||
a.updated_at,
|
||||
a.installation_id
|
||||
FROM activity_center_notifications a
|
||||
LEFT JOIN chats c
|
||||
ON
|
||||
|
@ -700,7 +718,8 @@ func (db sqlitePersistence) GetActivityCenterNotificationByID(id types.HexBytes)
|
|||
c.name,
|
||||
a.author,
|
||||
a.token_data,
|
||||
a.updated_at
|
||||
a.updated_at,
|
||||
a.installation_id
|
||||
FROM activity_center_notifications a
|
||||
LEFT JOIN chats c
|
||||
ON
|
||||
|
@ -1334,7 +1353,8 @@ func (db sqlitePersistence) ActiveContactRequestNotification(contactID string) (
|
|||
c.name,
|
||||
a.author,
|
||||
a.token_data,
|
||||
a.updated_at
|
||||
a.updated_at,
|
||||
a.installation_id
|
||||
FROM activity_center_notifications a
|
||||
LEFT JOIN chats c ON c.id = a.chat_id
|
||||
WHERE a.author = ?
|
||||
|
|
|
@ -3658,6 +3658,32 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
|||
return m.saveDataAndPrepareResponse(messageState)
|
||||
}
|
||||
|
||||
func (m *Messenger) deleteNotification(response *MessengerResponse, installationID string) error {
|
||||
notification, err := m.persistence.GetActivityCenterNotificationByID(types.FromHex(installationID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if notification == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
updatedAt := m.GetCurrentTimeInMillis()
|
||||
notification.UpdatedAt = updatedAt
|
||||
notification.Deleted = true
|
||||
// we shouldn't sync deleted notification here,
|
||||
// as the same user on different devices will receive the same message(CommunityCancelRequestToJoin) ?
|
||||
err = m.persistence.DeleteActivityCenterNotificationByID(types.FromHex(installationID), updatedAt)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to delete notification from Activity Center", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// sending signal to client to remove the activity center notification from UI
|
||||
response.AddActivityCenterNotification(notification)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Messenger) saveDataAndPrepareResponse(messageState *ReceivedMessageState) (*MessengerResponse, error) {
|
||||
var err error
|
||||
var contactsToSave []*Contact
|
||||
|
@ -3697,6 +3723,31 @@ func (m *Messenger) saveDataAndPrepareResponse(messageState *ReceivedMessageStat
|
|||
}
|
||||
}
|
||||
|
||||
if installation.Enabled {
|
||||
// Delete AC notif since the installation is now enabled
|
||||
err = m.deleteNotification(messageState.Response, id)
|
||||
if err != nil {
|
||||
m.logger.Error("error deleting notification", zap.Error(err))
|
||||
return false
|
||||
}
|
||||
} else if id != m.installationID {
|
||||
// Add activity center notification when we receive a new installation
|
||||
notification := &ActivityCenterNotification{
|
||||
ID: types.FromHex(id),
|
||||
Type: ActivityCenterNotificationTypeNewInstallationReceived,
|
||||
InstallationID: id,
|
||||
Timestamp: m.getTimesource().GetCurrentTime(),
|
||||
Read: false,
|
||||
Deleted: false,
|
||||
UpdatedAt: m.GetCurrentTimeInMillis(),
|
||||
}
|
||||
|
||||
err = m.addActivityCenterNotification(messageState.Response, notification, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"go.uber.org/zap"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/images"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||
|
@ -16,15 +17,30 @@ import (
|
|||
"github.com/status-im/status-go/protocol/requests"
|
||||
)
|
||||
|
||||
func (m *Messenger) EnableAndSyncInstallation(request *requests.EnableAndSyncInstallation) error {
|
||||
func (m *Messenger) EnableInstallationAndSync(request *requests.EnableInstallationAndSync) (*MessengerResponse, error) {
|
||||
if err := request.Validate(); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
err := m.EnableInstallation(request.InstallationID)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
return m.SyncDevices(context.Background(), "", "", nil)
|
||||
response, err := m.SendPairInstallation(context.Background(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = m.SyncDevices(context.Background(), "", "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Delete AC notif
|
||||
err = m.deleteNotification(response, request.InstallationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (m *Messenger) EnableInstallationAndPair(request *requests.EnableInstallationAndPair) (*MessengerResponse, error) {
|
||||
|
@ -53,7 +69,26 @@ func (m *Messenger) EnableInstallationAndPair(request *requests.EnableInstallati
|
|||
i.Enabled = true
|
||||
}
|
||||
m.allInstallations.Store(request.InstallationID, i)
|
||||
return m.SendPairInstallation(context.Background(), nil)
|
||||
response, err := m.SendPairInstallation(context.Background(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
notification := &ActivityCenterNotification{
|
||||
ID: types.FromHex(request.InstallationID),
|
||||
Type: ActivityCenterNotificationTypeNewInstallationCreated,
|
||||
InstallationID: m.installationID, // Put our own installation ID, as we're the initiator of the pairing
|
||||
Timestamp: m.getTimesource().GetCurrentTime(),
|
||||
Read: false,
|
||||
Deleted: false,
|
||||
UpdatedAt: m.GetCurrentTimeInMillis(),
|
||||
}
|
||||
|
||||
err = m.addActivityCenterNotification(response, notification, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, err
|
||||
}
|
||||
|
||||
// SendPairInstallation sends a pair installation message
|
||||
|
|
|
@ -102,7 +102,8 @@ func (s *MessengerPairingSuite) TestMessengerPairAfterSeedPhrase() {
|
|||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().NoError(alice1.EnableAndSyncInstallation(&requests.EnableAndSyncInstallation{InstallationID: installationID2}))
|
||||
_, err = alice1.EnableInstallationAndSync(&requests.EnableInstallationAndSync{InstallationID: installationID2})
|
||||
s.Require().NoError(err)
|
||||
|
||||
// check if the display name is synced
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
ALTER TABLE activity_center_notifications ADD COLUMN installation_id TEXT DEFAULT NULL;
|
|
@ -4,15 +4,15 @@ import (
|
|||
"errors"
|
||||
)
|
||||
|
||||
var ErrEnableAndSyncInstallationInvalidID = errors.New("enable and sync installation: invalid installation id")
|
||||
var ErrEnableInstallationAndSyncInvalidID = errors.New("enable installation and sync : invalid installation id")
|
||||
|
||||
type EnableAndSyncInstallation struct {
|
||||
type EnableInstallationAndSync struct {
|
||||
InstallationID string `json:"installationId"`
|
||||
}
|
||||
|
||||
func (j *EnableAndSyncInstallation) Validate() error {
|
||||
func (j *EnableInstallationAndSync) Validate() error {
|
||||
if len(j.InstallationID) == 0 {
|
||||
return ErrEnableAndSyncInstallationInvalidID
|
||||
return ErrEnableInstallationAndSyncInvalidID
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -59,13 +59,10 @@ func NewConnectionParams(netIPs []net.IP, port int, publicKey *ecdsa.PublicKey,
|
|||
// - AES encryption key
|
||||
// - string InstallationID of the sending device
|
||||
// - string KeyUID of the sending device
|
||||
//
|
||||
// NOTE:
|
||||
// - append(accrete) parameters instead of changing(breaking) existing parameters. Appending should **never** break, modifying existing parameters will break. Watch this before making changes: https://www.youtube.com/watch?v=oyLBGkS5ICk
|
||||
// - never strictly check version, unless you really want to break
|
||||
|
||||
// This flag is used to keep compatibility with 2.29. It will output a 5 parameters connection string with version 3.
|
||||
var keep229Compatibility bool = true
|
||||
|
||||
func (cp *ConnectionParams) ToString() string {
|
||||
v := base58.Encode(new(big.Int).SetInt64(int64(cp.version)).Bytes())
|
||||
ips := base58.Encode(SerializeNetIps(cp.netIPs))
|
||||
|
@ -73,18 +70,12 @@ func (cp *ConnectionParams) ToString() string {
|
|||
k := base58.Encode(elliptic.MarshalCompressed(cp.publicKey.Curve, cp.publicKey.X, cp.publicKey.Y))
|
||||
ek := base58.Encode(cp.aesKey)
|
||||
|
||||
if keep229Compatibility {
|
||||
return fmt.Sprintf("%s%s:%s:%s:%s:%s", connectionStringID, v, ips, p, k, ek)
|
||||
}
|
||||
|
||||
var i string
|
||||
if cp.installationID != "" {
|
||||
|
||||
u, err := uuid.Parse(cp.installationID)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse UUID: %v", err)
|
||||
} else {
|
||||
|
||||
// Convert UUID to byte slice
|
||||
byteSlice := u[:]
|
||||
i = base58.Encode(byteSlice)
|
||||
|
@ -94,7 +85,6 @@ func (cp *ConnectionParams) ToString() string {
|
|||
var kuid string
|
||||
if cp.keyUID != "" {
|
||||
kuid = base58.Encode([]byte(cp.keyUID))
|
||||
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%s:%s:%s:%s:%s:%s:%s", connectionStringID, v, ips, p, k, ek, i, kuid)
|
||||
|
|
|
@ -65,7 +65,6 @@ func (s *ConnectionParamsSuite) SetupSuite() {
|
|||
}
|
||||
|
||||
func (s *ConnectionParamsSuite) TestConnectionParams_ToString() {
|
||||
keep229Compatibility = false
|
||||
cp, err := s.server.MakeConnectionParams()
|
||||
s.Require().NoError(err)
|
||||
|
||||
|
|
|
@ -1063,8 +1063,13 @@ func (api *PublicAPI) SyncDevices(ctx context.Context, name, picture string) err
|
|||
return api.service.messenger.SyncDevices(ctx, name, picture, nil)
|
||||
}
|
||||
|
||||
func (api *PublicAPI) EnableAndSyncInstallation(request *requests.EnableAndSyncInstallation) error {
|
||||
return api.service.messenger.EnableAndSyncInstallation(request)
|
||||
// Deprecated: Use EnableInstallationAndSync instead
|
||||
func (api *PublicAPI) EnableAndSyncInstallation(request *requests.EnableInstallationAndSync) (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.EnableInstallationAndSync(request)
|
||||
}
|
||||
|
||||
func (api *PublicAPI) EnableInstallationAndSync(request *requests.EnableInstallationAndSync) (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.EnableInstallationAndSync(request)
|
||||
}
|
||||
|
||||
func (api *PublicAPI) EnableInstallationAndPair(request *requests.EnableInstallationAndPair) (*protocol.MessengerResponse, error) {
|
||||
|
|
Loading…
Reference in New Issue