feat(keycard): keycard details are being synced among devices

- sync all keycards state
- sync every keycard change
This commit is contained in:
Sale Djenic 2023-02-21 13:35:26 +01:00 committed by saledjenic
parent 30e20b42a0
commit 2d16e7b891
15 changed files with 2113 additions and 296 deletions

View File

@ -1 +1 @@
0.133.1
0.133.2

View File

@ -7,11 +7,10 @@ import (
"strings"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/protobuf"
)
const (
dbTransactionIsNil = "database transaction is nil"
)
var errDbTransactionIsNil = errors.New("keycard: database transaction is nil")
type KeyPair struct {
KeycardUID string `json:"keycard-uid"`
@ -22,6 +21,47 @@ type KeyPair struct {
LastUpdateClock uint64
}
type KeycardAction struct {
Action string `json:"action"`
OldKeycardUID string `json:"old-keycard-uid,omitempty"`
Keycard *KeyPair `json:"keycard"`
}
func (kp *KeyPair) ToSyncKeycard() *protobuf.SyncKeycard {
kc := &protobuf.SyncKeycard{
Uid: kp.KeycardUID,
Name: kp.KeycardName,
Locked: kp.KeycardLocked,
KeyUid: kp.KeyUID,
Clock: kp.LastUpdateClock,
}
for _, addr := range kp.AccountsAddresses {
kc.Addresses = append(kc.Addresses, addr.Bytes())
}
return kc
}
func (kp *KeyPair) FromSyncKeycard(kc *protobuf.SyncKeycard) {
kp.KeycardUID = kc.Uid
kp.KeycardName = kc.Name
kp.KeycardLocked = kc.Locked
kp.KeyUID = kc.KeyUid
kp.LastUpdateClock = kc.Clock
for _, addr := range kc.Addresses {
kp.AccountsAddresses = append(kp.AccountsAddresses, types.BytesToAddress(addr))
}
}
func removeElementAtIndex[T any](s []T, index int) []T {
if index < 0 || index >= len(s) {
panic("keycard: index out of the range")
}
return append(s[:index], s[index+1:]...)
}
type KeyPairs struct {
db *sql.DB
}
@ -150,7 +190,7 @@ func (kp *KeyPairs) startTransactionAndCheckIfNeedToProceed(kcUID string, clock
var dbLastUpdateClock uint64
err = tx.QueryRow(`SELECT last_update_clock FROM keycards WHERE keycard_uid = ?`, kcUID).Scan(&dbLastUpdateClock)
if err != nil {
return tx, false, err
return tx, err == sql.ErrNoRows, err
}
return tx, dbLastUpdateClock <= clock, nil
@ -158,7 +198,7 @@ func (kp *KeyPairs) startTransactionAndCheckIfNeedToProceed(kcUID string, clock
func (kp *KeyPairs) setLastUpdateClock(tx *sql.Tx, kcUID string, clock uint64) (err error) {
if tx == nil {
return errors.New(dbTransactionIsNil)
return errDbTransactionIsNil
}
_, err = tx.Exec(`
@ -176,7 +216,7 @@ func (kp *KeyPairs) setLastUpdateClock(tx *sql.Tx, kcUID string, clock uint64) (
func (kp *KeyPairs) getAccountsForKeycard(tx *sql.Tx, kcUID string) ([]types.Address, error) {
var accountAddresses []types.Address
if tx == nil {
return accountAddresses, errors.New(dbTransactionIsNil)
return accountAddresses, errDbTransactionIsNil
}
rows, err := tx.Query(`SELECT account_address FROM keycards_accounts WHERE keycard_uid = ?`, kcUID)
@ -199,7 +239,7 @@ func (kp *KeyPairs) getAccountsForKeycard(tx *sql.Tx, kcUID string) ([]types.Add
func (kp *KeyPairs) addAccounts(tx *sql.Tx, kcUID string, accountsAddresses []types.Address) (err error) {
if tx == nil {
return errors.New(dbTransactionIsNil)
return errDbTransactionIsNil
}
insertKcAcc, err := tx.Prepare(`
@ -232,7 +272,7 @@ func (kp *KeyPairs) addAccounts(tx *sql.Tx, kcUID string, accountsAddresses []ty
func (kp *KeyPairs) deleteKeycard(tx *sql.Tx, kcUID string) (err error) {
if tx == nil {
return errors.New(dbTransactionIsNil)
return errDbTransactionIsNil
}
delete, err := tx.Prepare(`
@ -252,7 +292,7 @@ func (kp *KeyPairs) deleteKeycard(tx *sql.Tx, kcUID string) (err error) {
return err
}
func (kp *KeyPairs) AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair KeyPair) (added bool, err error) {
func (kp *KeyPairs) AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair KeyPair) (addedKc bool, addedAccs bool, err error) {
tx, proceed, err := kp.startTransactionAndCheckIfNeedToProceed(keyPair.KeycardUID, keyPair.LastUpdateClock)
defer func() {
if err == nil {
@ -262,8 +302,9 @@ func (kp *KeyPairs) AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair KeyP
_ = tx.Rollback()
}()
if err != nil {
if err == sql.ErrNoRows {
if proceed {
// insert only if there is no such keycard, otherwise just add accounts
if err != nil && err == sql.ErrNoRows {
_, err = tx.Exec(`
INSERT INTO
keycards
@ -279,31 +320,117 @@ func (kp *KeyPairs) AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair KeyP
keyPair.KeycardUID, keyPair.KeycardName, keyPair.KeycardLocked, keyPair.KeyUID, keyPair.LastUpdateClock)
if err != nil {
return false, err
return false, false, err
}
err = kp.addAccounts(tx, keyPair.KeycardUID, keyPair.AccountsAddresses)
return err == nil, err
return err == nil, false, err
}
return false, err
}
if proceed {
err = kp.setLastUpdateClock(tx, keyPair.KeycardUID, keyPair.LastUpdateClock)
if err != nil {
return false, err
return false, false, err
}
err = kp.addAccounts(tx, keyPair.KeycardUID, keyPair.AccountsAddresses)
return err == nil, err
return false, err == nil, err
}
return false, nil
return false, false, err
}
func (kp *KeyPairs) SyncKeycards(syncingClock uint64, keypairsToSync []*KeyPair) (err error) {
tx, err := kp.db.Begin()
if err != nil {
return
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
_ = tx.Rollback()
}()
rows, err := tx.Query(`SELECT * FROM keycards`)
if err != nil && err != sql.ErrNoRows {
return err
}
defer rows.Close()
var dbKeypairs []*KeyPair
for rows.Next() {
keyPair := &KeyPair{}
err := rows.Scan(&keyPair.KeycardUID, &keyPair.KeycardName, &keyPair.KeycardLocked, &keyPair.KeyUID,
&keyPair.LastUpdateClock)
if err != nil {
return err
}
dbKeypairs = append(dbKeypairs, keyPair)
}
// apply those from `keypairsToSync` which are newer
for _, syncKp := range keypairsToSync {
foundAtIndex := -1
for i := range dbKeypairs {
if dbKeypairs[i].KeycardUID == syncKp.KeycardUID {
foundAtIndex = i
break
}
}
doInsertOrReplace := true
if foundAtIndex > -1 {
if dbKeypairs[foundAtIndex].LastUpdateClock > syncKp.LastUpdateClock {
doInsertOrReplace = false
}
dbKeypairs = removeElementAtIndex(dbKeypairs, foundAtIndex)
}
if doInsertOrReplace {
_, err = tx.Exec(`
INSERT OR REPLACE INTO
keycards
(
keycard_uid,
keycard_name,
keycard_locked,
key_uid,
last_update_clock
)
VALUES
(?, ?, ?, ?, ?);`,
syncKp.KeycardUID, syncKp.KeycardName, syncKp.KeycardLocked, syncKp.KeyUID, syncKp.LastUpdateClock)
if err != nil {
return err
}
err = kp.addAccounts(tx, syncKp.KeycardUID, syncKp.AccountsAddresses)
if err != nil {
return err
}
}
}
// remove those from the db if they are not in `keypairsToSync` and if they are older than the moment `keypairsToSync` was created at
for _, dbKp := range dbKeypairs {
if dbKp.LastUpdateClock > syncingClock {
continue
}
err = kp.deleteKeycard(tx, dbKp.KeycardUID)
if err != nil {
return err
}
}
return nil
}
func (kp *KeyPairs) RemoveMigratedAccountsForKeycard(kcUID string, accountAddresses []types.Address,
clock uint64) (removed bool, err error) {
clock uint64) (err error) {
tx, proceed, err := kp.startTransactionAndCheckIfNeedToProceed(kcUID, clock)
defer func() {
if err == nil {
@ -314,18 +441,18 @@ func (kp *KeyPairs) RemoveMigratedAccountsForKeycard(kcUID string, accountAddres
}()
if err != nil {
return false, err
return err
}
if proceed {
err = kp.setLastUpdateClock(tx, kcUID, clock)
if err != nil {
return false, err
return err
}
dbAccountAddresses, err := kp.getAccountsForKeycard(tx, kcUID)
if err != nil {
return false, err
return err
}
deleteKeycard := true
for _, dbAddr := range dbAccountAddresses {
@ -341,8 +468,7 @@ func (kp *KeyPairs) RemoveMigratedAccountsForKeycard(kcUID string, accountAddres
}
if deleteKeycard {
err = kp.deleteKeycard(tx, kcUID)
return err == nil, err
return kp.deleteKeycard(tx, kcUID)
}
inVector := strings.Repeat(",?", len(accountAddresses)-1)
@ -357,7 +483,7 @@ func (kp *KeyPairs) RemoveMigratedAccountsForKeycard(kcUID string, accountAddres
`
delete, err := tx.Prepare(query)
if err != nil {
return false, err
return err
}
args := make([]interface{}, len(accountAddresses)+1)
@ -370,13 +496,13 @@ func (kp *KeyPairs) RemoveMigratedAccountsForKeycard(kcUID string, accountAddres
_, err = delete.Exec(args...)
return true, err
return err
}
return false, nil
return err
}
func (kp *KeyPairs) execUpdateQuery(kcUID string, clock uint64, field string, value interface{}) (updated bool, err error) {
func (kp *KeyPairs) execUpdateQuery(kcUID string, clock uint64, field string, value interface{}) (err error) {
tx, proceed, err := kp.startTransactionAndCheckIfNeedToProceed(kcUID, clock)
defer func() {
if err == nil {
@ -387,35 +513,35 @@ func (kp *KeyPairs) execUpdateQuery(kcUID string, clock uint64, field string, va
}()
if err != nil {
return false, err
return err
}
if proceed {
sql := fmt.Sprintf(`UPDATE keycards SET %s = ?, last_update_clock = ? WHERE keycard_uid = ?`, field) // nolint: gosec
_, err = tx.Exec(sql, value, clock, kcUID)
return err == nil, err
return err
}
return false, nil
return nil
}
func (kp *KeyPairs) KeycardLocked(kcUID string, clock uint64) (updated bool, err error) {
func (kp *KeyPairs) KeycardLocked(kcUID string, clock uint64) (err error) {
return kp.execUpdateQuery(kcUID, clock, "keycard_locked", true)
}
func (kp *KeyPairs) KeycardUnlocked(kcUID string, clock uint64) (updated bool, err error) {
func (kp *KeyPairs) KeycardUnlocked(kcUID string, clock uint64) (err error) {
return kp.execUpdateQuery(kcUID, clock, "keycard_locked", false)
}
func (kp *KeyPairs) UpdateKeycardUID(oldKcUID string, newKcUID string, clock uint64) (updated bool, err error) {
func (kp *KeyPairs) UpdateKeycardUID(oldKcUID string, newKcUID string, clock uint64) (err error) {
return kp.execUpdateQuery(oldKcUID, clock, "keycard_uid", newKcUID)
}
func (kp *KeyPairs) SetKeycardName(kcUID string, kpName string, clock uint64) (updated bool, err error) {
func (kp *KeyPairs) SetKeycardName(kcUID string, kpName string, clock uint64) (err error) {
return kp.execUpdateQuery(kcUID, clock, "keycard_name", kpName)
}
func (kp *KeyPairs) DeleteKeycard(kcUID string, clock uint64) (deleted bool, err error) {
func (kp *KeyPairs) DeleteKeycard(kcUID string, clock uint64) (err error) {
tx, proceed, err := kp.startTransactionAndCheckIfNeedToProceed(kcUID, clock)
defer func() {
if err == nil {
@ -426,15 +552,14 @@ func (kp *KeyPairs) DeleteKeycard(kcUID string, clock uint64) (deleted bool, err
}()
if err != nil {
return false, err
return err
}
if proceed {
err = kp.deleteKeycard(tx, kcUID)
return err == nil, err
return kp.deleteKeycard(tx, kcUID)
}
return false, nil
return err
}
func (kp *KeyPairs) DeleteKeypair(keyUID string) (err error) {

View File

@ -62,34 +62,40 @@ func TestKeypairs(t *testing.T) {
}
// Test adding key pairs
result, err := db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair1)
addedKc, addedAccs, err := db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair1)
require.NoError(t, err)
require.Equal(t, true, result)
result, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair2)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
addedKc, addedAccs, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair2)
require.NoError(t, err)
require.Equal(t, true, result)
result, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair3)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
addedKc, addedAccs, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair3)
require.NoError(t, err)
require.Equal(t, true, result)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
// this should be added
result, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(KeyPair{
addedKc, addedAccs, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(KeyPair{
KeycardUID: keyPair3.KeycardUID,
AccountsAddresses: []types.Address{{0x03}},
LastUpdateClock: keyPair3.LastUpdateClock + 1,
})
require.NoError(t, err)
require.Equal(t, true, result)
require.Equal(t, false, addedKc)
require.Equal(t, true, addedAccs)
// this should not be added as it has clock value less than last updated clock value
result, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(KeyPair{
addedKc, addedAccs, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(KeyPair{
KeycardUID: keyPair3.KeycardUID,
AccountsAddresses: []types.Address{{0x04}},
LastUpdateClock: keyPair3.LastUpdateClock,
})
require.NoError(t, err)
require.Equal(t, false, result)
result, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair4)
require.Equal(t, false, addedKc)
require.Equal(t, false, addedAccs)
addedKc, addedAccs, err = db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(keyPair4)
require.NoError(t, err)
require.Equal(t, true, result)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
// Test reading migrated key pairs
rows, err := db.GetAllMigratedKeyPairs()
@ -156,9 +162,8 @@ func TestKeypairs(t *testing.T) {
}
// Test seting a new keycard name
result, err = db.SetKeycardName(keyPair1.KeycardUID, "Card101", 1000)
err = db.SetKeycardName(keyPair1.KeycardUID, "Card101", 1000)
require.NoError(t, err)
require.Equal(t, true, result)
rows, err = db.GetAllMigratedKeyPairs()
require.NoError(t, err)
newKeycardName := ""
@ -170,9 +175,8 @@ func TestKeypairs(t *testing.T) {
require.Equal(t, "Card101", newKeycardName)
// Test seting a new keycard name with an old clock value
result, err = db.SetKeycardName(keyPair1.KeycardUID, "Card102", 999) // clock is less than the last one
err = db.SetKeycardName(keyPair1.KeycardUID, "Card102", 999) // clock is less than the last one
require.NoError(t, err)
require.Equal(t, false, result)
rows, err = db.GetAllMigratedKeyPairs()
require.NoError(t, err)
newKeycardName = ""
@ -184,9 +188,8 @@ func TestKeypairs(t *testing.T) {
require.Equal(t, "Card101", newKeycardName)
// Test locking a keycard
result, err = db.KeycardLocked(keyPair1.KeycardUID, 1001)
err = db.KeycardLocked(keyPair1.KeycardUID, 1001)
require.NoError(t, err)
require.Equal(t, true, result)
rows, err = db.GetAllMigratedKeyPairs()
require.NoError(t, err)
locked := false
@ -201,9 +204,8 @@ func TestKeypairs(t *testing.T) {
const numOfAccountsToRemove = 2
require.Greater(t, len(keyPair1.AccountsAddresses), numOfAccountsToRemove)
accountsToRemove := keyPair1.AccountsAddresses[:numOfAccountsToRemove]
result, err = db.RemoveMigratedAccountsForKeycard(keyPair1.KeycardUID, accountsToRemove, 1002)
err = db.RemoveMigratedAccountsForKeycard(keyPair1.KeycardUID, accountsToRemove, 1002)
require.NoError(t, err)
require.Equal(t, true, result)
rows, err = db.GetMigratedKeyPairByKeyUID(keyPair1.KeyUID)
require.NoError(t, err)
require.Equal(t, 1, len(rows))
@ -211,9 +213,8 @@ func TestKeypairs(t *testing.T) {
// Test deleting accounts one by one, with the last deleted account keycard should be delete as well
for i, addr := range keyPair4.AccountsAddresses {
result, err = db.RemoveMigratedAccountsForKeycard(keyPair4.KeycardUID, []types.Address{addr}, 1003+uint64(i))
err = db.RemoveMigratedAccountsForKeycard(keyPair4.KeycardUID, []types.Address{addr}, 1003+uint64(i))
require.NoError(t, err)
require.Equal(t, true, result)
}
rows, err = db.GetAllMigratedKeyPairs()
require.NoError(t, err)
@ -227,14 +228,12 @@ func TestKeypairs(t *testing.T) {
require.Equal(t, true, deletedKeyPair4)
// Test update keycard uid
result, err = db.UpdateKeycardUID(keyPair1.KeycardUID, keycardUID, 1100)
err = db.UpdateKeycardUID(keyPair1.KeycardUID, keycardUID, 1100)
require.NoError(t, err)
require.Equal(t, true, result)
// Test unlocking a locked keycard
result, err = db.KeycardUnlocked(keycardUID, 1101)
err = db.KeycardUnlocked(keycardUID, 1101)
require.NoError(t, err)
require.Equal(t, true, result)
rows, err = db.GetAllMigratedKeyPairs()
require.NoError(t, err)
locked = true
@ -246,9 +245,8 @@ func TestKeypairs(t *testing.T) {
require.Equal(t, false, locked)
// Test detleting a keycard
result, err = db.DeleteKeycard(keycardUID, 1102)
err = db.DeleteKeycard(keycardUID, 1102)
require.NoError(t, err)
require.Equal(t, true, result)
rows, err = db.GetAllMigratedKeyPairs()
require.NoError(t, err)
require.Equal(t, 1, len(rows))

View File

@ -2348,6 +2348,12 @@ func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string,
return err
}
}
err = m.syncAllKeycards(ctx, rawMessageHandler)
if err != nil {
return err
}
return nil
}
@ -4102,6 +4108,34 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
allMessagesProcessed = false
continue
}
case protobuf.SyncAllKeycards:
if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
logger.Warn("not coming from us, ignoring")
continue
}
p := msg.ParsedMessage.Interface().(protobuf.SyncAllKeycards)
m.outputToCSV(msg.TransportMessage.Timestamp, msg.ID, senderID, filter.Topic, filter.ChatID, msg.Type, p)
err = m.handleSyncKeycards(messageState, p)
if err != nil {
logger.Warn("failed to handle SyncAllKeycards", zap.Error(err))
allMessagesProcessed = false
continue
}
case protobuf.SyncKeycardAction:
if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
logger.Warn("not coming from us, ignoring")
continue
}
p := msg.ParsedMessage.Interface().(protobuf.SyncKeycardAction)
m.outputToCSV(msg.TransportMessage.Timestamp, msg.ID, senderID, filter.Topic, filter.ChatID, msg.Type, p)
err = m.handleSyncKeycardActivity(messageState, p)
if err != nil {
logger.Warn("failed to handle SyncKeycardAction", zap.Error(err))
allMessagesProcessed = false
continue
}
default:
// Check if is an encrypted PushNotificationRegistration
if msg.Type == protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION {

View File

@ -0,0 +1,285 @@
package protocol
import (
"context"
"github.com/golang/protobuf/proto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/multiaccounts/keypairs"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
)
func (m *Messenger) dispatchSyncKeycard(ctx context.Context, chatID string, syncKeycard protobuf.SyncAllKeycards,
rawMessageHandler RawMessageHandler) error {
if !m.hasPairedDevices() {
return nil
}
encodedMessage, err := proto.Marshal(&syncKeycard)
if err != nil {
return err
}
rawMessage := common.RawMessage{
LocalChatID: chatID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_SYNC_ALL_KEYCARDS,
ResendAutomatically: true,
}
_, err = rawMessageHandler(ctx, rawMessage)
return err
}
func (m *Messenger) syncAllKeycards(ctx context.Context, rawMessageHandler RawMessageHandler) (err error) {
allKeycards, err := m.settings.GetAllKnownKeycards()
if err != nil {
return err
}
clock, chat := m.getLastClockWithRelatedChat()
message := protobuf.SyncAllKeycards{}
message.Clock = clock
for _, kc := range allKeycards {
syncKeycard := kc.ToSyncKeycard()
if syncKeycard.Clock == 0 {
syncKeycard.Clock = clock
}
message.Keycards = append(message.Keycards, syncKeycard)
}
err = m.dispatchSyncKeycard(ctx, chat.ID, message, rawMessageHandler)
if err != nil {
return err
}
chat.LastClockValue = clock
return m.saveChat(chat)
}
func (m *Messenger) handleSyncKeycards(state *ReceivedMessageState, syncMessage protobuf.SyncAllKeycards) (err error) {
var keypairsToSync []*keypairs.KeyPair
for _, syncKc := range syncMessage.Keycards {
var kp = &keypairs.KeyPair{}
kp.FromSyncKeycard(syncKc)
keypairsToSync = append(keypairsToSync, kp)
}
err = m.settings.SyncKeycards(syncMessage.Clock, keypairsToSync)
if err != nil {
return err
}
allKeycards, err := m.settings.GetAllKnownKeycards()
if err != nil {
return err
}
state.Response.AddAllKnownKeycards(allKeycards)
return nil
}
func (m *Messenger) dispatchKeycardActivity(ctx context.Context, syncMessage protobuf.SyncKeycardAction) error {
if !m.hasPairedDevices() {
return nil
}
clock, chat := m.getLastClockWithRelatedChat()
encodedMessage, err := proto.Marshal(&syncMessage)
if err != nil {
return err
}
rawMessage := common.RawMessage{
LocalChatID: chat.ID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_SYNC_KEYCARD_ACTION,
ResendAutomatically: true,
}
_, err = m.dispatchMessage(ctx, rawMessage)
if err != nil {
return err
}
chat.LastClockValue = clock
return m.saveChat(chat)
}
func (m *Messenger) handleSyncKeycardActivity(state *ReceivedMessageState, syncMessage protobuf.SyncKeycardAction) (err error) {
var kcAction = &keypairs.KeycardAction{
Action: protobuf.SyncKeycardAction_Action_name[int32(syncMessage.Action)],
OldKeycardUID: syncMessage.OldKeycardUid,
Keycard: &keypairs.KeyPair{},
}
kcAction.Keycard.FromSyncKeycard(syncMessage.Keycard)
switch syncMessage.Action {
case protobuf.SyncKeycardAction_KEYCARD_ADDED,
protobuf.SyncKeycardAction_ACCOUNTS_ADDED:
_, _, err = m.settings.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kcAction.Keycard)
case protobuf.SyncKeycardAction_KEYCARD_DELETED:
err = m.settings.DeleteKeycard(kcAction.Keycard.KeycardUID, kcAction.Keycard.LastUpdateClock)
case protobuf.SyncKeycardAction_ACCOUNTS_REMOVED:
err = m.settings.RemoveMigratedAccountsForKeycard(kcAction.Keycard.KeycardUID, kcAction.Keycard.AccountsAddresses,
kcAction.Keycard.LastUpdateClock)
case protobuf.SyncKeycardAction_LOCKED:
err = m.settings.KeycardLocked(kcAction.Keycard.KeycardUID, kcAction.Keycard.LastUpdateClock)
case protobuf.SyncKeycardAction_UNLOCKED:
err = m.settings.KeycardUnlocked(kcAction.Keycard.KeycardUID, kcAction.Keycard.LastUpdateClock)
case protobuf.SyncKeycardAction_UID_UPDATED:
err = m.settings.UpdateKeycardUID(kcAction.OldKeycardUID, kcAction.Keycard.KeycardUID,
kcAction.Keycard.LastUpdateClock)
case protobuf.SyncKeycardAction_NAME_CHANGED:
err = m.settings.SetKeycardName(kcAction.Keycard.KeycardUID, kcAction.Keycard.KeycardName,
kcAction.Keycard.LastUpdateClock)
default:
panic("unknown action for handling keycard activity")
}
if err != nil {
return err
}
state.Response.AddKeycardAction(kcAction)
return nil
}
func (m *Messenger) AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(ctx context.Context, kp *keypairs.KeyPair) (added bool, err error) {
addedKc, addedAccs, err := m.settings.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
if err != nil {
return addedKc || addedAccs, err
}
activityMessage := protobuf.SyncKeycardAction{
Keycard: kp.ToSyncKeycard(),
}
if addedKc {
activityMessage.Action = protobuf.SyncKeycardAction_KEYCARD_ADDED
} else if addedAccs {
activityMessage.Action = protobuf.SyncKeycardAction_ACCOUNTS_ADDED
}
return addedKc || addedAccs, m.dispatchKeycardActivity(ctx, activityMessage)
}
func (m *Messenger) RemoveMigratedAccountsForKeycard(ctx context.Context, kcUID string, accountAddresses []string, clock uint64) error {
var addresses []types.Address
for _, addr := range accountAddresses {
addresses = append(addresses, types.HexToAddress(addr))
}
err := m.settings.RemoveMigratedAccountsForKeycard(kcUID, addresses, clock)
if err != nil {
return err
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_ACCOUNTS_REMOVED,
Keycard: &protobuf.SyncKeycard{
Uid: kcUID,
Clock: clock,
},
}
for _, addr := range addresses {
activityMessage.Keycard.Addresses = append(activityMessage.Keycard.Addresses, addr.Bytes())
}
return m.dispatchKeycardActivity(ctx, activityMessage)
}
func (m *Messenger) SetKeycardName(ctx context.Context, kcUID string, kpName string, clock uint64) error {
err := m.settings.SetKeycardName(kcUID, kpName, clock)
if err != nil {
return err
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_NAME_CHANGED,
Keycard: &protobuf.SyncKeycard{
Uid: kcUID,
Name: kpName,
Clock: clock,
},
}
return m.dispatchKeycardActivity(ctx, activityMessage)
}
func (m *Messenger) KeycardLocked(ctx context.Context, kcUID string, clock uint64) error {
err := m.settings.KeycardLocked(kcUID, clock)
if err != nil {
return err
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_LOCKED,
Keycard: &protobuf.SyncKeycard{
Uid: kcUID,
Clock: clock,
},
}
return m.dispatchKeycardActivity(ctx, activityMessage)
}
func (m *Messenger) KeycardUnlocked(ctx context.Context, kcUID string, clock uint64) error {
err := m.settings.KeycardUnlocked(kcUID, clock)
if err != nil {
return err
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_UNLOCKED,
Keycard: &protobuf.SyncKeycard{
Uid: kcUID,
Clock: clock,
},
}
return m.dispatchKeycardActivity(ctx, activityMessage)
}
func (m *Messenger) DeleteKeycard(ctx context.Context, kcUID string, clock uint64) error {
err := m.settings.DeleteKeycard(kcUID, clock)
if err != nil {
return err
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_KEYCARD_DELETED,
Keycard: &protobuf.SyncKeycard{
Uid: kcUID,
Clock: clock,
},
}
return m.dispatchKeycardActivity(ctx, activityMessage)
}
func (m *Messenger) UpdateKeycardUID(ctx context.Context, oldKcUID string, newKcUID string, clock uint64) error {
err := m.settings.UpdateKeycardUID(oldKcUID, newKcUID, clock)
if err != nil {
return err
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_UID_UPDATED,
OldKeycardUid: oldKcUID,
Keycard: &protobuf.SyncKeycard{
Uid: newKcUID,
Clock: clock,
},
}
return m.dispatchKeycardActivity(ctx, activityMessage)
}

View File

@ -9,6 +9,7 @@ import (
"github.com/status-im/status-go/appmetrics"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/multiaccounts/keypairs"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/communities"
@ -69,6 +70,8 @@ type MessengerResponse struct {
trustStatus map[string]verification.TrustStatus
emojiReactions map[string]*EmojiReaction
savedAddresses map[string]*wallet.SavedAddress
keycards []*keypairs.KeyPair
keycardActions []*keypairs.KeycardAction
}
func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
@ -107,6 +110,8 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
DiscordMessages []*protobuf.DiscordMessage `json:"discordMessages,omitempty"`
DiscordMessageAttachments []*protobuf.DiscordMessageAttachment `json:"discordMessageAtachments,omitempty"`
SavedAddresses []*wallet.SavedAddress `json:"savedAddresses,omitempty"`
Keycards []*keypairs.KeyPair `json:"keycards,omitempty"`
KeycardActions []*keypairs.KeycardAction `json:"keycardActions,omitempty"`
}{
Contacts: r.Contacts,
Installations: r.Installations,
@ -138,6 +143,8 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
DiscordCategories: r.DiscordCategories,
DiscordChannels: r.DiscordChannels,
DiscordOldestMessageTimestamp: r.DiscordOldestMessageTimestamp,
Keycards: r.AllKnownKeycards(),
KeycardActions: r.KeycardActions(),
}
responseItem.TrustStatus = r.TrustStatus()
@ -262,6 +269,8 @@ func (r *MessengerResponse) IsEmpty() bool {
len(r.verificationRequests)+
len(r.RequestsToJoinCommunity) == 0 &&
len(r.savedAddresses) == 0 &&
len(r.keycards) == 0 &&
len(r.keycardActions) == 0 &&
r.currentStatus == nil &&
r.activityCenterState == nil
}
@ -293,6 +302,8 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error {
r.AddEmojiReactions(response.EmojiReactions())
r.AddInstallations(response.Installations)
r.AddSavedAddresses(response.SavedAddresses())
r.AddAllKnownKeycards(response.AllKnownKeycards())
r.AddKeycardActions(response.KeycardActions())
r.CommunityChanges = append(r.CommunityChanges, response.CommunityChanges...)
return nil
@ -424,6 +435,26 @@ func (r *MessengerResponse) SavedAddresses() []*wallet.SavedAddress {
return ers
}
func (r *MessengerResponse) AddAllKnownKeycards(keycards []*keypairs.KeyPair) {
r.keycards = append(r.keycards, keycards...)
}
func (r *MessengerResponse) AllKnownKeycards() []*keypairs.KeyPair {
return r.keycards
}
func (r *MessengerResponse) AddKeycardAction(keycardAction *keypairs.KeycardAction) {
r.keycardActions = append(r.keycardActions, keycardAction)
}
func (r *MessengerResponse) AddKeycardActions(keycardActions []*keypairs.KeycardAction) {
r.keycardActions = append(r.keycardActions, keycardActions...)
}
func (r *MessengerResponse) KeycardActions() []*keypairs.KeycardAction {
return r.keycardActions
}
func (r *MessengerResponse) AddNotification(n *localnotifications.Notification) {
if r.notifications == nil {
r.notifications = make(map[string]*localnotifications.Notification)

View File

@ -0,0 +1,620 @@
package protocol
import (
"context"
"crypto/ecdsa"
"testing"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/waku"
)
func TestMessengerSyncKeycardChangeSuite(t *testing.T) {
suite.Run(t, new(MessengerSyncKeycardChangeSuite))
}
type MessengerSyncKeycardChangeSuite struct {
suite.Suite
main *Messenger // main instance of Messenger paired with `other`
other *Messenger
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
// If one wants to send messages between different instances of Messenger,
// a single Waku service should be shared.
shh types.Waku
logger *zap.Logger
}
func (s *MessengerSyncKeycardChangeSuite) SetupTest() {
s.logger = tt.MustCreateTestLogger()
config := waku.DefaultConfig
config.MinimumAcceptedPoW = 0
shh := waku.New(&config, s.logger)
s.shh = gethbridge.NewGethWakuWrapper(shh)
s.Require().NoError(shh.Start())
s.main = s.newMessenger(s.shh)
s.privateKey = s.main.identity
// Start the main messenger in order to receive installations
_, err := s.main.Start()
s.Require().NoError(err)
// Create new device and add main account to
s.other, err = newMessengerWithKey(s.shh, s.main.identity, s.logger, nil)
s.Require().NoError(err)
// Pair devices (main and other)
imOther := &multidevice.InstallationMetadata{
Name: "other-device",
DeviceType: "other-device-type",
}
err = s.other.SetInstallationMetadata(s.other.installationID, imOther)
s.Require().NoError(err)
response, err := s.other.SendPairInstallation(context.Background())
s.Require().NoError(err)
s.Require().NotNil(response)
// Wait for the message to reach its destination
_, err = WaitOnMessengerResponse(
s.main,
func(r *MessengerResponse) bool { return len(r.Installations) > 0 },
"installation not received",
)
s.Require().NoError(err)
err = s.main.EnableInstallation(s.other.installationID)
s.Require().NoError(err)
}
func (s *MessengerSyncKeycardChangeSuite) TearDownTest() {
s.Require().NoError(s.other.Shutdown())
s.Require().NoError(s.main.Shutdown())
}
func (s *MessengerSyncKeycardChangeSuite) newMessenger(shh types.Waku) *Messenger {
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
messenger, err := newMessengerWithKey(s.shh, privateKey, s.logger, nil)
s.Require().NoError(err)
return messenger
}
func (s *MessengerSyncKeycardChangeSuite) TestAddingNewKeycards() {
dbOnReceiver := s.other.settings
// Add key cards on sender
allKeycardsToSync := getKeycardsForTest()[:2]
for _, kp := range allKeycardsToSync {
added, err := s.main.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(context.Background(), kp)
s.Require().NoError(err)
s.Require().Equal(true, added)
}
// Wait for the response
_, err := WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == len(allKeycardsToSync)
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards))
s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards))
}
func (s *MessengerSyncKeycardChangeSuite) TestAddingAccountsToKeycard() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add additional accounts to sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.AccountsAddresses = []types.Address{{0x011}, {0x022}, {0x033}, {0x044}}
added, err := s.main.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(context.Background(), updatedKeycard)
s.Require().NoError(err)
s.Require().Equal(true, added)
// Add accounts that we can check for results later
updatedKeycard.AccountsAddresses = append(updatedKeycard.AccountsAddresses, keycardToSync.AccountsAddresses...)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(syncedKeycards[0], updatedKeycard))
}
func (s *MessengerSyncKeycardChangeSuite) TestRemovingAccountsFromKeycard() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
var accountAddressesToRemove []string
for _, acc := range keycardToSync.AccountsAddresses[:2] {
accountAddressesToRemove = append(accountAddressesToRemove, acc.String())
}
// Remove accounts from sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.AccountsAddresses = updatedKeycard.AccountsAddresses[2:]
err = s.main.RemoveMigratedAccountsForKeycard(context.Background(), keycardToSync.KeycardUID,
accountAddressesToRemove, keycardToSync.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestRemovingAllAccountsFromKeycard() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
var accountAddressesToRemove []string
for _, acc := range keycardToSync.AccountsAddresses {
accountAddressesToRemove = append(accountAddressesToRemove, acc.String())
}
// Remove all accounts from sender
err = s.main.RemoveMigratedAccountsForKeycard(context.Background(), keycardToSync.KeycardUID,
accountAddressesToRemove, keycardToSync.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(0, len(syncedKeycards))
}
func (s *MessengerSyncKeycardChangeSuite) TestDeleteKeycard() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Remove keycard from sender
err = s.main.DeleteKeycard(context.Background(), keycardToSync.KeycardUID, keycardToSync.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(0, len(syncedKeycards))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardName() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Set new keycard name to sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.KeycardName = "New Keycard Name"
updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock + 1
err = s.main.SetKeycardName(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.KeycardName,
updatedKeycard.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardNameWithOlderClock() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Set new keycard name to sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.KeycardName = "New Keycard Name"
updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock - 1
err = s.main.SetKeycardName(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.KeycardName,
updatedKeycard.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(keycardToSync, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLocked() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Set keycard locked on sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.KeycardLocked = true
updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock + 1
err = s.main.KeycardLocked(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLockedOlderClock() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Set keycard locked on sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.KeycardLocked = true
updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock - 1
err = s.main.KeycardLocked(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(keycardToSync, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlocked() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
keycardToSync.KeycardLocked = true
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Set keycard unlocked on sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.KeycardLocked = false
updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock + 1
err = s.main.KeycardUnlocked(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlockedOlderClock() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
keycardToSync.KeycardLocked = true
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Set keycard unlocked on sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.KeycardLocked = false
updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock - 1
err = s.main.KeycardLocked(context.Background(), updatedKeycard.KeycardUID, updatedKeycard.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(keycardToSync, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUid() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Set keycard unlocked on sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.KeycardUID = "00000000000000000000000000000000"
updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock + 1
err = s.main.UpdateKeycardUID(context.Background(), keycardToSync.KeycardUID, updatedKeycard.KeycardUID,
updatedKeycard.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(updatedKeycard, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUidOldClock() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycard on sender
keycardToSync := getKeycardsForTest()[:1][0]
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*keycardToSync)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Set keycard unlocked on sender
updatedKeycard := getKeycardsForTest()[:1][0]
updatedKeycard.KeycardUID = "00000000000000000000000000000000"
updatedKeycard.LastUpdateClock = updatedKeycard.LastUpdateClock - 1
err = s.main.UpdateKeycardUID(context.Background(), keycardToSync.KeycardUID, updatedKeycard.KeycardUID,
updatedKeycard.LastUpdateClock)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(sameKeycards(keycardToSync, syncedKeycards[0]))
}

View File

@ -0,0 +1,437 @@
package protocol
import (
"context"
"crypto/ecdsa"
"testing"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/multiaccounts/keypairs"
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/waku"
)
func TestMessengerSyncKeycardsStateSuite(t *testing.T) {
suite.Run(t, new(MessengerSyncKeycardsStateSuite))
}
type MessengerSyncKeycardsStateSuite struct {
suite.Suite
main *Messenger // main instance of Messenger paired with `other`
other *Messenger
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
// If one wants to send messages between different instances of Messenger,
// a single Waku service should be shared.
shh types.Waku
logger *zap.Logger
}
func (s *MessengerSyncKeycardsStateSuite) SetupTest() {
s.logger = tt.MustCreateTestLogger()
config := waku.DefaultConfig
config.MinimumAcceptedPoW = 0
shh := waku.New(&config, s.logger)
s.shh = gethbridge.NewGethWakuWrapper(shh)
s.Require().NoError(shh.Start())
s.main = s.newMessenger(s.shh)
s.privateKey = s.main.identity
// Start the main messenger in order to receive installations
_, err := s.main.Start()
s.Require().NoError(err)
// Create new device and add main account to
s.other, err = newMessengerWithKey(s.shh, s.main.identity, s.logger, nil)
s.Require().NoError(err)
// Pair devices (main and other)
imOther := &multidevice.InstallationMetadata{
Name: "other-device",
DeviceType: "other-device-type",
}
err = s.other.SetInstallationMetadata(s.other.installationID, imOther)
s.Require().NoError(err)
response, err := s.other.SendPairInstallation(context.Background())
s.Require().NoError(err)
s.Require().NotNil(response)
// Wait for the message to reach its destination
_, err = WaitOnMessengerResponse(
s.main,
func(r *MessengerResponse) bool { return len(r.Installations) > 0 },
"installation not received",
)
s.Require().NoError(err)
err = s.main.EnableInstallation(s.other.installationID)
s.Require().NoError(err)
}
func (s *MessengerSyncKeycardsStateSuite) TearDownTest() {
s.Require().NoError(s.other.Shutdown())
s.Require().NoError(s.main.Shutdown())
}
func (s *MessengerSyncKeycardsStateSuite) newMessenger(shh types.Waku) *Messenger {
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
messenger, err := newMessengerWithKey(s.shh, privateKey, s.logger, nil)
s.Require().NoError(err)
return messenger
}
func sameKeycards(a, b *keypairs.KeyPair) bool {
same := a.KeycardUID == b.KeycardUID &&
a.KeyUID == b.KeyUID &&
a.KeycardName == b.KeycardName &&
a.KeycardLocked == b.KeycardLocked &&
a.LastUpdateClock == b.LastUpdateClock &&
len(a.AccountsAddresses) == len(b.AccountsAddresses)
if same {
for i := range a.AccountsAddresses {
found := false
for j := range b.AccountsAddresses {
if a.AccountsAddresses[i] == b.AccountsAddresses[j] {
found = true
break
}
}
if !found {
return false
}
}
}
return same
}
func getKeycardsForTest() []*keypairs.KeyPair {
keyPair1 := keypairs.KeyPair{
KeycardUID: "00000000000000000000000000000001",
KeycardName: "Card01",
KeycardLocked: false,
AccountsAddresses: []types.Address{{0x01}, {0x02}, {0x03}, {0x04}},
KeyUID: "0000000000000000000000000000000000000000000000000000000000000001",
LastUpdateClock: 100,
}
keyPair2 := keypairs.KeyPair{
KeycardUID: "00000000000000000000000000000002",
KeycardName: "Card02",
KeycardLocked: false,
AccountsAddresses: []types.Address{{0x01}, {0x02}},
KeyUID: "0000000000000000000000000000000000000000000000000000000000000002",
LastUpdateClock: 200,
}
keyPair3 := keypairs.KeyPair{
KeycardUID: "00000000000000000000000000000003",
KeycardName: "Card02 Copy",
KeycardLocked: false,
AccountsAddresses: []types.Address{{0x01}, {0x02}},
KeyUID: "0000000000000000000000000000000000000000000000000000000000000002",
LastUpdateClock: 300,
}
keyPair4 := keypairs.KeyPair{
KeycardUID: "00000000000000000000000000000004",
KeycardName: "Card04",
KeycardLocked: false,
AccountsAddresses: []types.Address{{0x01}, {0x02}, {0x03}},
KeyUID: "0000000000000000000000000000000000000000000000000000000000000004",
LastUpdateClock: 400,
}
return []*keypairs.KeyPair{&keyPair1, &keyPair2, &keyPair3, &keyPair4}
}
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNoKeycards() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycards on sender
allKeycardsToSync := getKeycardsForTest()
for _, kp := range allKeycardsToSync {
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Trigger's a sync between devices
err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.AllKnownKeycards()) == len(allKeycardsToSync)
},
"expected to receive keycards",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards))
s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards))
}
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasKeycardsOlderThanSender() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycards on sender
allKeycardsToSync := getKeycardsForTest()
for _, kp := range allKeycardsToSync {
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Add keycards on receiver
keycardsOnReceiver := getKeycardsForTest()[:2]
keycardsOnReceiver[0].KeycardName = "CardNameToBeChanged-0"
keycardsOnReceiver[0].AccountsAddresses = keycardsOnReceiver[0].AccountsAddresses[2:3]
keycardsOnReceiver[0].LastUpdateClock = keycardsOnReceiver[0].LastUpdateClock - 1
keycardsOnReceiver[1].KeycardName = "CardNameToBeChanged-1"
keycardsOnReceiver[1].LastUpdateClock = keycardsOnReceiver[1].LastUpdateClock - 1
for _, kp := range keycardsOnReceiver {
addedKc, addedAccs, err := dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Trigger's a sync between devices
err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.AllKnownKeycards()) == len(allKeycardsToSync)
},
"expected to receive keycards",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards))
s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards))
}
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfKeycardsWereDeletedOnSenderSide() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycards on sender
allKeycardsToSync := getKeycardsForTest()[:2]
for _, kp := range allKeycardsToSync {
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Add keycards on receiver
keycardsOnReceiver := getKeycardsForTest()
for _, kp := range keycardsOnReceiver {
addedKc, addedAccs, err := dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Trigger's a sync between devices
err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.AllKnownKeycards()) == len(allKeycardsToSync)
},
"expected to receive keycards",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards))
s.Require().True(haveSameElements(syncedKeycards, allKeycardsToSync, sameKeycards))
}
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNewerKeycardsThanTheSameAreDeletedOnSenderSide() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycards on sender
allKeycardsToSync := getKeycardsForTest()[:2]
for _, kp := range allKeycardsToSync {
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Add keycards on receiver
keycardsOnReceiver := getKeycardsForTest()
clock, _ := s.other.getLastClockWithRelatedChat()
keycardsOnReceiver[2].KeycardName = "NewerCardName-2"
keycardsOnReceiver[2].LastUpdateClock = clock + 1000
keycardsOnReceiver[3].KeycardName = "NewerCardName-3"
keycardsOnReceiver[3].LastUpdateClock = clock + 1000
for _, kp := range keycardsOnReceiver {
addedKc, addedAccs, err := dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Trigger's a sync between devices
err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.AllKnownKeycards()) >= len(allKeycardsToSync)
},
"expected to receive keycards",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(len(keycardsOnReceiver), len(syncedKeycards))
for _, kc := range allKeycardsToSync {
s.Require().True(contains(syncedKeycards, kc, sameKeycards))
}
for _, kc := range keycardsOnReceiver {
s.Require().True(contains(syncedKeycards, kc, sameKeycards))
}
}
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverAndSenderHasNoKeycardsInCommon() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycards on sender
allKeycardsToSync := getKeycardsForTest()[:2]
for _, kp := range allKeycardsToSync {
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Add keycards on receiver
keycardsOnReceiver := getKeycardsForTest()[2:]
clock, _ := s.other.getLastClockWithRelatedChat()
keycardsOnReceiver[0].KeycardName = "NewerCardName-0"
keycardsOnReceiver[0].LastUpdateClock = clock + 1000
keycardsOnReceiver[1].KeycardName = "NewerCardName-1"
keycardsOnReceiver[1].LastUpdateClock = clock + 1000
for _, kp := range keycardsOnReceiver {
addedKc, addedAccs, err := dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Trigger's a sync between devices
err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.AllKnownKeycards()) >= len(allKeycardsToSync)
},
"expected to receive keycards",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(len(allKeycardsToSync)+len(keycardsOnReceiver), len(syncedKeycards))
for _, kc := range allKeycardsToSync {
s.Require().True(contains(syncedKeycards, kc, sameKeycards))
}
for _, kc := range keycardsOnReceiver {
s.Require().True(contains(syncedKeycards, kc, sameKeycards))
}
}
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNewerKeycardThanSender() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// Add keycards on sender
allKeycardsToSync := getKeycardsForTest()
for _, kp := range allKeycardsToSync {
addedKc, addedAccs, err := senderDb.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Add keycards on receiver
keycardsOnReceiver := getKeycardsForTest()[2:]
clock, _ := s.other.getLastClockWithRelatedChat()
keycardsOnReceiver[0].KeycardName = "NewerCardName-0"
keycardsOnReceiver[0].LastUpdateClock = clock + 1000
keycardsOnReceiver[1].KeycardName = "NewerCardName-1"
keycardsOnReceiver[1].LastUpdateClock = clock + 1000
for _, kp := range keycardsOnReceiver {
addedKc, addedAccs, err := dbOnReceiver.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(*kp)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
}
// Trigger's a sync between devices
err := s.main.SyncDevices(context.Background(), "ens-name", "profile-image", nil)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.AllKnownKeycards()) == len(allKeycardsToSync)
},
"expected to receive keycards",
)
s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(len(allKeycardsToSync), len(syncedKeycards))
for _, kc := range allKeycardsToSync[:2] {
s.Require().True(contains(syncedKeycards, kc, sameKeycards))
}
for _, kc := range keycardsOnReceiver {
s.Require().True(contains(syncedKeycards, kc, sameKeycards))
}
}

View File

@ -188,6 +188,17 @@ func (m *Messenger) HandleSyncRawMessages(rawMessages []*protobuf.RawMessage) er
m.logger.Error("failed to handleSyncSavedAddress when HandleSyncRawMessages", zap.Error(err))
continue
}
case protobuf.ApplicationMetadataMessage_SYNC_ALL_KEYCARDS:
var message protobuf.SyncAllKeycards
err := proto.Unmarshal(rawMessage.GetPayload(), &message)
if err != nil {
return err
}
err = m.handleSyncKeycards(state, message)
if err != nil {
m.logger.Error("failed to handleSyncKeycards when HandleSyncRawMessages", zap.Error(err))
continue
}
}
}
response, err := m.saveDataAndPrepareResponse(state)

View File

@ -84,6 +84,8 @@ const (
ApplicationMetadataMessage_SYNC_SAVED_ADDRESS ApplicationMetadataMessage_Type = 59
ApplicationMetadataMessage_COMMUNITY_CANCEL_REQUEST_TO_JOIN ApplicationMetadataMessage_Type = 60
ApplicationMetadataMessage_CANCEL_CONTACT_VERIFICATION ApplicationMetadataMessage_Type = 61
ApplicationMetadataMessage_SYNC_ALL_KEYCARDS ApplicationMetadataMessage_Type = 62
ApplicationMetadataMessage_SYNC_KEYCARD_ACTION ApplicationMetadataMessage_Type = 63
)
var ApplicationMetadataMessage_Type_name = map[int32]string{
@ -148,6 +150,8 @@ var ApplicationMetadataMessage_Type_name = map[int32]string{
59: "SYNC_SAVED_ADDRESS",
60: "COMMUNITY_CANCEL_REQUEST_TO_JOIN",
61: "CANCEL_CONTACT_VERIFICATION",
62: "SYNC_ALL_KEYCARDS",
63: "SYNC_KEYCARD_ACTION",
}
var ApplicationMetadataMessage_Type_value = map[string]int32{
@ -212,6 +216,8 @@ var ApplicationMetadataMessage_Type_value = map[string]int32{
"SYNC_SAVED_ADDRESS": 59,
"COMMUNITY_CANCEL_REQUEST_TO_JOIN": 60,
"CANCEL_CONTACT_VERIFICATION": 61,
"SYNC_ALL_KEYCARDS": 62,
"SYNC_KEYCARD_ACTION": 63,
}
func (x ApplicationMetadataMessage_Type) String() string {
@ -290,62 +296,63 @@ func init() {
}
var fileDescriptor_ad09a6406fcf24c7 = []byte{
// 908 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0x5b, 0x73, 0x13, 0x37,
0x14, 0x6e, 0x20, 0x4d, 0x40, 0xb9, 0xa0, 0x88, 0x5c, 0x9c, 0xbb, 0x31, 0x34, 0x04, 0x68, 0x4d,
0x0b, 0x6d, 0xa7, 0x2d, 0xe5, 0x41, 0x96, 0x4e, 0x6c, 0xe1, 0x5d, 0x69, 0x91, 0xb4, 0x66, 0xdc,
0x17, 0xcd, 0x52, 0x5c, 0x26, 0x33, 0x40, 0x3c, 0xc4, 0x3c, 0xe4, 0x9f, 0xf6, 0x57, 0xf4, 0x37,
0x74, 0xb4, 0x57, 0x27, 0xd9, 0x90, 0xa7, 0x64, 0xcf, 0xf7, 0xe9, 0x48, 0xe7, 0x3b, 0xdf, 0x39,
0x46, 0xad, 0x64, 0x3c, 0xfe, 0x70, 0xfc, 0x77, 0x32, 0x39, 0x3e, 0xf9, 0xe4, 0x3e, 0x8e, 0x26,
0xc9, 0xbb, 0x64, 0x92, 0xb8, 0x8f, 0xa3, 0xd3, 0xd3, 0xe4, 0xfd, 0xa8, 0x3d, 0xfe, 0x7c, 0x32,
0x39, 0x21, 0xb7, 0xd2, 0x3f, 0x6f, 0xbf, 0xfc, 0xd3, 0xfa, 0x6f, 0x19, 0x6d, 0xd1, 0xea, 0x40,
0x98, 0xf3, 0xc3, 0x8c, 0x4e, 0x76, 0xd0, 0xed, 0xd3, 0xe3, 0xf7, 0x9f, 0x92, 0xc9, 0x97, 0xcf,
0xa3, 0xc6, 0x4c, 0x73, 0xe6, 0x70, 0x51, 0x57, 0x01, 0xd2, 0x40, 0xf3, 0xe3, 0xe4, 0xec, 0xc3,
0x49, 0xf2, 0xae, 0x71, 0x23, 0xc5, 0x8a, 0x4f, 0xf2, 0x12, 0xcd, 0x4e, 0xce, 0xc6, 0xa3, 0xc6,
0xcd, 0xe6, 0xcc, 0xe1, 0xf2, 0xb3, 0x47, 0xed, 0xe2, 0xbe, 0xf6, 0xd5, 0x77, 0xb5, 0xed, 0xd9,
0x78, 0xa4, 0xd3, 0x63, 0xad, 0x7f, 0x97, 0xd0, 0xac, 0xff, 0x24, 0x0b, 0x68, 0x3e, 0x96, 0x7d,
0xa9, 0xde, 0x48, 0xfc, 0x0d, 0xc1, 0x68, 0x91, 0xf5, 0xa8, 0x75, 0x21, 0x18, 0x43, 0xbb, 0x80,
0x67, 0x08, 0x41, 0xcb, 0x4c, 0x49, 0x4b, 0x99, 0x75, 0x71, 0xc4, 0xa9, 0x05, 0x7c, 0x83, 0xec,
0xa2, 0xcd, 0x10, 0xc2, 0x0e, 0x68, 0xd3, 0x13, 0x51, 0x1e, 0x2e, 0x8f, 0xdc, 0x24, 0x6b, 0x68,
0x25, 0xa2, 0x42, 0x3b, 0x21, 0x8d, 0xa5, 0x41, 0x40, 0xad, 0x50, 0x12, 0xcf, 0xfa, 0xb0, 0x19,
0x4a, 0x76, 0x3e, 0xfc, 0x2d, 0xb9, 0x8f, 0xf6, 0x35, 0xbc, 0x8e, 0xc1, 0x58, 0x47, 0x39, 0xd7,
0x60, 0x8c, 0x3b, 0x52, 0xda, 0x59, 0x4d, 0xa5, 0xa1, 0x2c, 0x25, 0xcd, 0x91, 0xc7, 0xe8, 0x80,
0x32, 0x06, 0x91, 0x75, 0xd7, 0x71, 0xe7, 0xc9, 0x13, 0xf4, 0x90, 0x03, 0x0b, 0x84, 0x84, 0x6b,
0xc9, 0xb7, 0xc8, 0x06, 0xba, 0x5b, 0x90, 0xa6, 0x81, 0xdb, 0x64, 0x15, 0x61, 0x03, 0x92, 0x9f,
0x8b, 0x22, 0xb2, 0x8f, 0xb6, 0x2f, 0xe6, 0x9e, 0x26, 0x2c, 0x78, 0x69, 0x2e, 0x15, 0xe9, 0x72,
0x01, 0xf1, 0x62, 0x3d, 0x4c, 0x19, 0x53, 0xb1, 0xb4, 0x78, 0x89, 0xdc, 0x43, 0xbb, 0x97, 0xe1,
0x28, 0xee, 0x04, 0x82, 0x39, 0xdf, 0x17, 0xbc, 0x4c, 0xf6, 0xd0, 0x56, 0xd1, 0x0f, 0xa6, 0x38,
0x38, 0xca, 0x07, 0xa0, 0xad, 0x30, 0x10, 0x82, 0xb4, 0xf8, 0x0e, 0x69, 0xa1, 0xbd, 0x28, 0x36,
0x3d, 0x27, 0x95, 0x15, 0x47, 0x82, 0x65, 0x29, 0x34, 0x74, 0x85, 0xb1, 0x3a, 0x93, 0x1c, 0x7b,
0x85, 0xbe, 0xce, 0x71, 0x1a, 0x4c, 0xa4, 0xa4, 0x01, 0xbc, 0x42, 0xb6, 0xd1, 0xc6, 0x65, 0xf2,
0xeb, 0x18, 0xf4, 0x10, 0x13, 0xf2, 0x00, 0x35, 0xaf, 0x00, 0xab, 0x14, 0x77, 0x7d, 0xd5, 0x75,
0xf7, 0xa5, 0xfa, 0xe1, 0x55, 0x5f, 0x52, 0x1d, 0x9c, 0x1f, 0x5f, 0xf3, 0x16, 0x84, 0x50, 0xbd,
0x12, 0x4e, 0x43, 0xae, 0xf3, 0x3a, 0xd9, 0x44, 0x6b, 0x5d, 0xad, 0xe2, 0x28, 0x95, 0xc5, 0x09,
0x39, 0x10, 0x36, 0xab, 0x6e, 0x83, 0xac, 0xa0, 0xa5, 0x2c, 0xc8, 0x41, 0x5a, 0x61, 0x87, 0xb8,
0xe1, 0xd9, 0x4c, 0x85, 0x61, 0x2c, 0x85, 0x1d, 0x3a, 0x0e, 0x86, 0x69, 0x11, 0xa5, 0xec, 0x4d,
0xd2, 0x40, 0xab, 0x15, 0x34, 0x95, 0x67, 0xcb, 0xbf, 0xba, 0x42, 0xca, 0x6e, 0x2b, 0xf7, 0x4a,
0x09, 0x89, 0xb7, 0xc9, 0x1d, 0xb4, 0x10, 0x09, 0x59, 0xda, 0x7e, 0xc7, 0xcf, 0x0e, 0x70, 0x51,
0xcd, 0xce, 0xae, 0x7f, 0x89, 0xb1, 0xd4, 0xc6, 0xa6, 0x18, 0x9d, 0x3d, 0x5f, 0x0b, 0x87, 0x00,
0xa6, 0xe6, 0x65, 0xdf, 0x9b, 0xaa, 0xce, 0x33, 0xf9, 0xd5, 0xb8, 0x49, 0xb6, 0xd0, 0x3a, 0x95,
0x4a, 0x0e, 0x43, 0x15, 0x1b, 0x17, 0x82, 0xd5, 0x82, 0xb9, 0x0e, 0xb5, 0xac, 0x87, 0xef, 0x95,
0x53, 0x95, 0x96, 0xac, 0x21, 0x54, 0x03, 0xe0, 0xb8, 0xe5, 0xbb, 0x56, 0x85, 0xf3, 0xab, 0x8c,
0x17, 0x90, 0xe3, 0xfb, 0x04, 0xa1, 0xb9, 0x0e, 0x65, 0xfd, 0x38, 0xc2, 0x0f, 0x4a, 0x47, 0x7a,
0x65, 0x07, 0xbe, 0x52, 0x06, 0xd2, 0x82, 0xce, 0xa8, 0xdf, 0x95, 0x8e, 0xbc, 0x08, 0x67, 0xd3,
0x08, 0x1c, 0x1f, 0x78, 0xc7, 0xd5, 0x52, 0xb8, 0x30, 0xa1, 0x30, 0x06, 0x38, 0x7e, 0x98, 0x2a,
0xe1, 0x39, 0x1d, 0xa5, 0xfa, 0x21, 0xd5, 0x7d, 0x7c, 0x48, 0xd6, 0x11, 0xc9, 0x5e, 0x18, 0x00,
0xd5, 0xae, 0x27, 0x8c, 0x55, 0x7a, 0x88, 0x1f, 0x79, 0x19, 0xd3, 0xb8, 0x01, 0x6b, 0x85, 0xec,
0xe2, 0xc7, 0xa4, 0x89, 0x76, 0xaa, 0x46, 0x50, 0xcd, 0x7a, 0x62, 0x00, 0x2e, 0xa4, 0x5d, 0x09,
0x36, 0x10, 0xb2, 0x8f, 0x9f, 0xf8, 0x26, 0xa6, 0x67, 0x22, 0xad, 0x8e, 0x44, 0x00, 0x2e, 0x12,
0xcc, 0xc6, 0x1a, 0xf0, 0xf7, 0x7e, 0xbe, 0x53, 0xe4, 0x0d, 0x0d, 0x02, 0xb0, 0xe5, 0xa8, 0xfd,
0x90, 0x6a, 0x9a, 0x6d, 0x94, 0x62, 0x9c, 0x0a, 0x43, 0xb6, 0xbd, 0x78, 0x1a, 0xac, 0xce, 0x66,
0xec, 0x3c, 0xf8, 0x94, 0x1c, 0xa0, 0xd6, 0x95, 0xb6, 0xa8, 0x5c, 0xfb, 0x63, 0xd5, 0x81, 0x92,
0x9c, 0x57, 0x64, 0xf0, 0x4f, 0xbe, 0xa4, 0xe2, 0x68, 0x71, 0xc3, 0x00, 0x74, 0xe9, 0x7e, 0xfc,
0xcc, 0x9b, 0xe2, 0xc2, 0xfb, 0xce, 0x11, 0x9e, 0xfb, 0x14, 0xc5, 0x2a, 0xaa, 0x65, 0xfc, 0x5c,
0x5a, 0xc3, 0xea, 0xd8, 0x58, 0xe0, 0x2e, 0x36, 0xa0, 0xf1, 0x2f, 0x65, 0xc7, 0xa7, 0xd9, 0x65,
0x7d, 0xbf, 0x96, 0x1d, 0xbf, 0x50, 0xb9, 0xe3, 0xc0, 0x84, 0xf1, 0x89, 0x7f, 0xcb, 0x76, 0x50,
0x8d, 0x04, 0x01, 0xd0, 0x01, 0xe0, 0xdf, 0x3d, 0x9e, 0xa6, 0xc8, 0x9d, 0xee, 0xb7, 0x6e, 0x58,
0x19, 0xfe, 0x8f, 0xb2, 0xf5, 0x86, 0x0e, 0x80, 0x17, 0xcb, 0x19, 0xbf, 0xf0, 0xdb, 0xa4, 0xca,
0xcb, 0xa8, 0x64, 0x10, 0x5c, 0x1a, 0xbc, 0x3f, 0xbd, 0x32, 0x39, 0x56, 0x5b, 0xf7, 0xcb, 0xce,
0xd2, 0x5f, 0x0b, 0xed, 0xa7, 0x2f, 0x8a, 0xdf, 0xc3, 0xb7, 0x73, 0xe9, 0x7f, 0xcf, 0xff, 0x0f,
0x00, 0x00, 0xff, 0xff, 0x84, 0x77, 0xdc, 0x48, 0xb6, 0x07, 0x00, 0x00,
// 928 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0x6b, 0x73, 0x13, 0x37,
0x14, 0x6d, 0x20, 0x4d, 0x40, 0x79, 0x29, 0x22, 0x0f, 0xe7, 0x6d, 0x0c, 0x0d, 0x01, 0x5a, 0xd3,
0x42, 0xdb, 0x69, 0x4b, 0x69, 0x47, 0x96, 0x6e, 0x6c, 0xe1, 0x5d, 0x69, 0x91, 0xb4, 0x66, 0xdc,
0x2f, 0x9a, 0xa5, 0xb8, 0x4c, 0x66, 0x80, 0x78, 0x88, 0xf9, 0x90, 0x7f, 0xd0, 0x5f, 0xd1, 0xdf,
0xda, 0xd1, 0x3e, 0x9d, 0xd8, 0x21, 0x9f, 0x92, 0xbd, 0xf7, 0xe8, 0x4a, 0xe7, 0xdc, 0x73, 0xaf,
0x51, 0x23, 0x19, 0x0e, 0xdf, 0x9f, 0xfc, 0x9d, 0x8c, 0x4e, 0x4e, 0x3f, 0xba, 0x0f, 0x83, 0x51,
0xf2, 0x36, 0x19, 0x25, 0xee, 0xc3, 0xe0, 0xec, 0x2c, 0x79, 0x37, 0x68, 0x0e, 0x3f, 0x9d, 0x8e,
0x4e, 0xc9, 0xad, 0xf4, 0xcf, 0x9b, 0xcf, 0xff, 0x34, 0xfe, 0x5b, 0x41, 0xdb, 0xb4, 0x3a, 0x10,
0xe6, 0xf8, 0x30, 0x83, 0x93, 0x5d, 0x74, 0xfb, 0xec, 0xe4, 0xdd, 0xc7, 0x64, 0xf4, 0xf9, 0xd3,
0xa0, 0x36, 0x53, 0x9f, 0x39, 0x5a, 0xd4, 0x55, 0x80, 0xd4, 0xd0, 0xfc, 0x30, 0x39, 0x7f, 0x7f,
0x9a, 0xbc, 0xad, 0xdd, 0x48, 0x73, 0xc5, 0x27, 0x79, 0x81, 0x66, 0x47, 0xe7, 0xc3, 0x41, 0xed,
0x66, 0x7d, 0xe6, 0x68, 0xf9, 0xe9, 0xc3, 0x66, 0x71, 0x5f, 0xf3, 0xea, 0xbb, 0x9a, 0xf6, 0x7c,
0x38, 0xd0, 0xe9, 0xb1, 0xc6, 0xbf, 0xcb, 0x68, 0xd6, 0x7f, 0x92, 0x05, 0x34, 0x1f, 0xcb, 0xae,
0x54, 0xaf, 0x25, 0xfe, 0x8a, 0x60, 0xb4, 0xc8, 0x3a, 0xd4, 0xba, 0x10, 0x8c, 0xa1, 0x6d, 0xc0,
0x33, 0x84, 0xa0, 0x65, 0xa6, 0xa4, 0xa5, 0xcc, 0xba, 0x38, 0xe2, 0xd4, 0x02, 0xbe, 0x41, 0xf6,
0xd0, 0x56, 0x08, 0x61, 0x0b, 0xb4, 0xe9, 0x88, 0x28, 0x0f, 0x97, 0x47, 0x6e, 0x92, 0x75, 0xb4,
0x1a, 0x51, 0xa1, 0x9d, 0x90, 0xc6, 0xd2, 0x20, 0xa0, 0x56, 0x28, 0x89, 0x67, 0x7d, 0xd8, 0xf4,
0x25, 0xbb, 0x18, 0xfe, 0x9a, 0xdc, 0x43, 0x07, 0x1a, 0x5e, 0xc5, 0x60, 0xac, 0xa3, 0x9c, 0x6b,
0x30, 0xc6, 0x1d, 0x2b, 0xed, 0xac, 0xa6, 0xd2, 0x50, 0x96, 0x82, 0xe6, 0xc8, 0x23, 0x74, 0x48,
0x19, 0x83, 0xc8, 0xba, 0xeb, 0xb0, 0xf3, 0xe4, 0x31, 0x7a, 0xc0, 0x81, 0x05, 0x42, 0xc2, 0xb5,
0xe0, 0x5b, 0x64, 0x13, 0xdd, 0x29, 0x40, 0xe3, 0x89, 0xdb, 0x64, 0x0d, 0x61, 0x03, 0x92, 0x5f,
0x88, 0x22, 0x72, 0x80, 0x76, 0x2e, 0xd7, 0x1e, 0x07, 0x2c, 0x78, 0x69, 0x26, 0x48, 0xba, 0x5c,
0x40, 0xbc, 0x38, 0x3d, 0x4d, 0x19, 0x53, 0xb1, 0xb4, 0x78, 0x89, 0xdc, 0x45, 0x7b, 0x93, 0xe9,
0x28, 0x6e, 0x05, 0x82, 0x39, 0xdf, 0x17, 0xbc, 0x4c, 0xf6, 0xd1, 0x76, 0xd1, 0x0f, 0xa6, 0x38,
0x38, 0xca, 0x7b, 0xa0, 0xad, 0x30, 0x10, 0x82, 0xb4, 0x78, 0x85, 0x34, 0xd0, 0x7e, 0x14, 0x9b,
0x8e, 0x93, 0xca, 0x8a, 0x63, 0xc1, 0xb2, 0x12, 0x1a, 0xda, 0xc2, 0x58, 0x9d, 0x49, 0x8e, 0xbd,
0x42, 0x5f, 0xc6, 0x38, 0x0d, 0x26, 0x52, 0xd2, 0x00, 0x5e, 0x25, 0x3b, 0x68, 0x73, 0x12, 0xfc,
0x2a, 0x06, 0xdd, 0xc7, 0x84, 0xdc, 0x47, 0xf5, 0x2b, 0x92, 0x55, 0x89, 0x3b, 0x9e, 0xf5, 0xb4,
0xfb, 0x52, 0xfd, 0xf0, 0x9a, 0xa7, 0x34, 0x2d, 0x9d, 0x1f, 0x5f, 0xf7, 0x16, 0x84, 0x50, 0xbd,
0x14, 0x4e, 0x43, 0xae, 0xf3, 0x06, 0xd9, 0x42, 0xeb, 0x6d, 0xad, 0xe2, 0x28, 0x95, 0xc5, 0x09,
0xd9, 0x13, 0x36, 0x63, 0xb7, 0x49, 0x56, 0xd1, 0x52, 0x16, 0xe4, 0x20, 0xad, 0xb0, 0x7d, 0x5c,
0xf3, 0x68, 0xa6, 0xc2, 0x30, 0x96, 0xc2, 0xf6, 0x1d, 0x07, 0xc3, 0xb4, 0x88, 0x52, 0xf4, 0x16,
0xa9, 0xa1, 0xb5, 0x2a, 0x35, 0x56, 0x67, 0xdb, 0xbf, 0xba, 0xca, 0x94, 0xdd, 0x56, 0xee, 0xa5,
0x12, 0x12, 0xef, 0x90, 0x15, 0xb4, 0x10, 0x09, 0x59, 0xda, 0x7e, 0xd7, 0xcf, 0x0e, 0x70, 0x51,
0xcd, 0xce, 0x9e, 0x7f, 0x89, 0xb1, 0xd4, 0xc6, 0xa6, 0x18, 0x9d, 0x7d, 0xcf, 0x85, 0x43, 0x00,
0x63, 0xf3, 0x72, 0xe0, 0x4d, 0x35, 0xcd, 0x33, 0xf9, 0xd5, 0xb8, 0x4e, 0xb6, 0xd1, 0x06, 0x95,
0x4a, 0xf6, 0x43, 0x15, 0x1b, 0x17, 0x82, 0xd5, 0x82, 0xb9, 0x16, 0xb5, 0xac, 0x83, 0xef, 0x96,
0x53, 0x95, 0x52, 0xd6, 0x10, 0xaa, 0x1e, 0x70, 0xdc, 0xf0, 0x5d, 0xab, 0xc2, 0xf9, 0x55, 0xc6,
0x0b, 0xc8, 0xf1, 0x3d, 0x82, 0xd0, 0x5c, 0x8b, 0xb2, 0x6e, 0x1c, 0xe1, 0xfb, 0xa5, 0x23, 0xbd,
0xb2, 0x3d, 0xcf, 0x94, 0x81, 0xb4, 0xa0, 0x33, 0xe8, 0x37, 0xa5, 0x23, 0x2f, 0xa7, 0xb3, 0x69,
0x04, 0x8e, 0x0f, 0xbd, 0xe3, 0xa6, 0x42, 0xb8, 0x30, 0xa1, 0x30, 0x06, 0x38, 0x7e, 0x90, 0x2a,
0xe1, 0x31, 0x2d, 0xa5, 0xba, 0x21, 0xd5, 0x5d, 0x7c, 0x44, 0x36, 0x10, 0xc9, 0x5e, 0x18, 0x00,
0xd5, 0xae, 0x23, 0x8c, 0x55, 0xba, 0x8f, 0x1f, 0x7a, 0x19, 0xd3, 0xb8, 0x01, 0x6b, 0x85, 0x6c,
0xe3, 0x47, 0xa4, 0x8e, 0x76, 0xab, 0x46, 0x50, 0xcd, 0x3a, 0xa2, 0x07, 0x2e, 0xa4, 0x6d, 0x09,
0x36, 0x10, 0xb2, 0x8b, 0x1f, 0xfb, 0x26, 0xa6, 0x67, 0x22, 0xad, 0x8e, 0x45, 0x00, 0x2e, 0x12,
0xcc, 0xc6, 0x1a, 0xf0, 0xb7, 0x7e, 0xbe, 0xd3, 0xcc, 0x6b, 0x1a, 0x04, 0x60, 0xcb, 0x51, 0xfb,
0x2e, 0xd5, 0x34, 0xdb, 0x28, 0xc5, 0x38, 0x15, 0x86, 0x6c, 0x7a, 0xf1, 0x34, 0x58, 0x9d, 0xcd,
0xd8, 0xc5, 0xe4, 0x13, 0x72, 0x88, 0x1a, 0x57, 0xda, 0xa2, 0x72, 0xed, 0xf7, 0x55, 0x07, 0x4a,
0x70, 0xce, 0xc8, 0xe0, 0x1f, 0x3c, 0xa5, 0xe2, 0x68, 0x71, 0x43, 0x0f, 0x74, 0xe9, 0x7e, 0xfc,
0xd4, 0x9b, 0xe2, 0xd2, 0xfb, 0x2e, 0x00, 0x9e, 0xf9, 0x12, 0xc5, 0x2a, 0x9a, 0x8a, 0xf8, 0xb1,
0xb4, 0x86, 0xd5, 0xb1, 0xb1, 0xc0, 0x5d, 0x6c, 0x40, 0xe3, 0x9f, 0xca, 0x8e, 0x8f, 0xa3, 0x4b,
0x7e, 0x3f, 0x97, 0x1d, 0xbf, 0xc4, 0xdc, 0x71, 0x60, 0xc2, 0xf8, 0xc2, 0xbf, 0x64, 0x3b, 0x68,
0x8a, 0x04, 0x01, 0xd0, 0x1e, 0xe0, 0x5f, 0x7d, 0x3e, 0x2d, 0x91, 0x3b, 0xdd, 0x6f, 0xdd, 0xb0,
0x32, 0xfc, 0x6f, 0x65, 0xeb, 0x0d, 0xed, 0x01, 0x2f, 0x96, 0x33, 0x7e, 0xee, 0xb7, 0x49, 0x55,
0x97, 0x51, 0xc9, 0x20, 0x98, 0x18, 0xbc, 0xdf, 0xbd, 0x32, 0x79, 0x6e, 0x2a, 0xef, 0x17, 0x25,
0x6f, 0x1a, 0x04, 0xae, 0x0b, 0x7d, 0x46, 0x35, 0x37, 0xf8, 0x8f, 0xd2, 0x0a, 0x79, 0xc8, 0xe5,
0xbb, 0xe4, 0xcf, 0xd6, 0xd2, 0x5f, 0x0b, 0xcd, 0x27, 0xcf, 0x8b, 0xdf, 0xcf, 0x37, 0x73, 0xe9,
0x7f, 0xcf, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x4d, 0xc7, 0x99, 0x73, 0xe6, 0x07, 0x00, 0x00,
}

View File

@ -74,5 +74,7 @@ message ApplicationMetadataMessage {
SYNC_SAVED_ADDRESS = 59;
COMMUNITY_CANCEL_REQUEST_TO_JOIN = 60;
CANCEL_CONTACT_VERIFICATION = 61;
SYNC_ALL_KEYCARDS = 62;
SYNC_KEYCARD_ACTION = 63;
}
}

View File

@ -107,6 +107,49 @@ func (SyncContactRequestDecision_DecisionStatus) EnumDescriptor() ([]byte, []int
return fileDescriptor_d61ab7221f0b5518, []int{27, 0}
}
type SyncKeycardAction_Action int32
const (
SyncKeycardAction_KEYCARD_ADDED SyncKeycardAction_Action = 0
SyncKeycardAction_ACCOUNTS_ADDED SyncKeycardAction_Action = 1
SyncKeycardAction_KEYCARD_DELETED SyncKeycardAction_Action = 2
SyncKeycardAction_ACCOUNTS_REMOVED SyncKeycardAction_Action = 3
SyncKeycardAction_LOCKED SyncKeycardAction_Action = 4
SyncKeycardAction_UNLOCKED SyncKeycardAction_Action = 5
SyncKeycardAction_UID_UPDATED SyncKeycardAction_Action = 6
SyncKeycardAction_NAME_CHANGED SyncKeycardAction_Action = 7
)
var SyncKeycardAction_Action_name = map[int32]string{
0: "KEYCARD_ADDED",
1: "ACCOUNTS_ADDED",
2: "KEYCARD_DELETED",
3: "ACCOUNTS_REMOVED",
4: "LOCKED",
5: "UNLOCKED",
6: "UID_UPDATED",
7: "NAME_CHANGED",
}
var SyncKeycardAction_Action_value = map[string]int32{
"KEYCARD_ADDED": 0,
"ACCOUNTS_ADDED": 1,
"KEYCARD_DELETED": 2,
"ACCOUNTS_REMOVED": 3,
"LOCKED": 4,
"UNLOCKED": 5,
"UID_UPDATED": 6,
"NAME_CHANGED": 7,
}
func (x SyncKeycardAction_Action) String() string {
return proto.EnumName(SyncKeycardAction_Action_name, int32(x))
}
func (SyncKeycardAction_Action) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_d61ab7221f0b5518, []int{32, 0}
}
// `FetchingBackedUpDataDetails` is used to describe how many messages a single backup data structure consists of
type FetchingBackedUpDataDetails struct {
DataNumber uint32 `protobuf:"varint,1,opt,name=data_number,json=dataNumber,proto3" json:"data_number,omitempty"`
@ -2486,10 +2529,192 @@ func (m *SyncRawMessage) GetSettingsJsonBytes() []byte {
return nil
}
type SyncKeycard struct {
Uid string `protobuf:"bytes,1,opt,name=uid,proto3" json:"uid,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Locked bool `protobuf:"varint,3,opt,name=locked,proto3" json:"locked,omitempty"`
KeyUid string `protobuf:"bytes,4,opt,name=key_uid,json=keyUid,proto3" json:"key_uid,omitempty"`
Addresses [][]byte `protobuf:"bytes,5,rep,name=addresses,proto3" json:"addresses,omitempty"`
Clock uint64 `protobuf:"varint,6,opt,name=clock,proto3" json:"clock,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SyncKeycard) Reset() { *m = SyncKeycard{} }
func (m *SyncKeycard) String() string { return proto.CompactTextString(m) }
func (*SyncKeycard) ProtoMessage() {}
func (*SyncKeycard) Descriptor() ([]byte, []int) {
return fileDescriptor_d61ab7221f0b5518, []int{31}
}
func (m *SyncKeycard) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SyncKeycard.Unmarshal(m, b)
}
func (m *SyncKeycard) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SyncKeycard.Marshal(b, m, deterministic)
}
func (m *SyncKeycard) XXX_Merge(src proto.Message) {
xxx_messageInfo_SyncKeycard.Merge(m, src)
}
func (m *SyncKeycard) XXX_Size() int {
return xxx_messageInfo_SyncKeycard.Size(m)
}
func (m *SyncKeycard) XXX_DiscardUnknown() {
xxx_messageInfo_SyncKeycard.DiscardUnknown(m)
}
var xxx_messageInfo_SyncKeycard proto.InternalMessageInfo
func (m *SyncKeycard) GetUid() string {
if m != nil {
return m.Uid
}
return ""
}
func (m *SyncKeycard) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *SyncKeycard) GetLocked() bool {
if m != nil {
return m.Locked
}
return false
}
func (m *SyncKeycard) GetKeyUid() string {
if m != nil {
return m.KeyUid
}
return ""
}
func (m *SyncKeycard) GetAddresses() [][]byte {
if m != nil {
return m.Addresses
}
return nil
}
func (m *SyncKeycard) GetClock() uint64 {
if m != nil {
return m.Clock
}
return 0
}
type SyncKeycardAction struct {
Action SyncKeycardAction_Action `protobuf:"varint,1,opt,name=action,proto3,enum=protobuf.SyncKeycardAction_Action" json:"action,omitempty"`
OldKeycardUid string `protobuf:"bytes,2,opt,name=oldKeycardUid,proto3" json:"oldKeycardUid,omitempty"`
Keycard *SyncKeycard `protobuf:"bytes,3,opt,name=keycard,proto3" json:"keycard,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SyncKeycardAction) Reset() { *m = SyncKeycardAction{} }
func (m *SyncKeycardAction) String() string { return proto.CompactTextString(m) }
func (*SyncKeycardAction) ProtoMessage() {}
func (*SyncKeycardAction) Descriptor() ([]byte, []int) {
return fileDescriptor_d61ab7221f0b5518, []int{32}
}
func (m *SyncKeycardAction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SyncKeycardAction.Unmarshal(m, b)
}
func (m *SyncKeycardAction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SyncKeycardAction.Marshal(b, m, deterministic)
}
func (m *SyncKeycardAction) XXX_Merge(src proto.Message) {
xxx_messageInfo_SyncKeycardAction.Merge(m, src)
}
func (m *SyncKeycardAction) XXX_Size() int {
return xxx_messageInfo_SyncKeycardAction.Size(m)
}
func (m *SyncKeycardAction) XXX_DiscardUnknown() {
xxx_messageInfo_SyncKeycardAction.DiscardUnknown(m)
}
var xxx_messageInfo_SyncKeycardAction proto.InternalMessageInfo
func (m *SyncKeycardAction) GetAction() SyncKeycardAction_Action {
if m != nil {
return m.Action
}
return SyncKeycardAction_KEYCARD_ADDED
}
func (m *SyncKeycardAction) GetOldKeycardUid() string {
if m != nil {
return m.OldKeycardUid
}
return ""
}
func (m *SyncKeycardAction) GetKeycard() *SyncKeycard {
if m != nil {
return m.Keycard
}
return nil
}
type SyncAllKeycards struct {
Keycards []*SyncKeycard `protobuf:"bytes,1,rep,name=keycards,proto3" json:"keycards,omitempty"`
Clock uint64 `protobuf:"varint,2,opt,name=clock,proto3" json:"clock,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SyncAllKeycards) Reset() { *m = SyncAllKeycards{} }
func (m *SyncAllKeycards) String() string { return proto.CompactTextString(m) }
func (*SyncAllKeycards) ProtoMessage() {}
func (*SyncAllKeycards) Descriptor() ([]byte, []int) {
return fileDescriptor_d61ab7221f0b5518, []int{33}
}
func (m *SyncAllKeycards) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SyncAllKeycards.Unmarshal(m, b)
}
func (m *SyncAllKeycards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SyncAllKeycards.Marshal(b, m, deterministic)
}
func (m *SyncAllKeycards) XXX_Merge(src proto.Message) {
xxx_messageInfo_SyncAllKeycards.Merge(m, src)
}
func (m *SyncAllKeycards) XXX_Size() int {
return xxx_messageInfo_SyncAllKeycards.Size(m)
}
func (m *SyncAllKeycards) XXX_DiscardUnknown() {
xxx_messageInfo_SyncAllKeycards.DiscardUnknown(m)
}
var xxx_messageInfo_SyncAllKeycards proto.InternalMessageInfo
func (m *SyncAllKeycards) GetKeycards() []*SyncKeycard {
if m != nil {
return m.Keycards
}
return nil
}
func (m *SyncAllKeycards) GetClock() uint64 {
if m != nil {
return m.Clock
}
return 0
}
func init() {
proto.RegisterEnum("protobuf.SyncTrustedUser_TrustStatus", SyncTrustedUser_TrustStatus_name, SyncTrustedUser_TrustStatus_value)
proto.RegisterEnum("protobuf.SyncVerificationRequest_VerificationStatus", SyncVerificationRequest_VerificationStatus_name, SyncVerificationRequest_VerificationStatus_value)
proto.RegisterEnum("protobuf.SyncContactRequestDecision_DecisionStatus", SyncContactRequestDecision_DecisionStatus_name, SyncContactRequestDecision_DecisionStatus_value)
proto.RegisterEnum("protobuf.SyncKeycardAction_Action", SyncKeycardAction_Action_name, SyncKeycardAction_Action_value)
proto.RegisterType((*FetchingBackedUpDataDetails)(nil), "protobuf.FetchingBackedUpDataDetails")
proto.RegisterType((*Backup)(nil), "protobuf.Backup")
proto.RegisterType((*MultiAccount)(nil), "protobuf.MultiAccount")
@ -2524,6 +2749,9 @@ func init() {
proto.RegisterType((*BackedUpProfile)(nil), "protobuf.BackedUpProfile")
proto.RegisterType((*RawMessage)(nil), "protobuf.RawMessage")
proto.RegisterType((*SyncRawMessage)(nil), "protobuf.SyncRawMessage")
proto.RegisterType((*SyncKeycard)(nil), "protobuf.SyncKeycard")
proto.RegisterType((*SyncKeycardAction)(nil), "protobuf.SyncKeycardAction")
proto.RegisterType((*SyncAllKeycards)(nil), "protobuf.SyncAllKeycards")
}
func init() {
@ -2531,153 +2759,168 @@ func init() {
}
var fileDescriptor_d61ab7221f0b5518 = []byte{
// 2361 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x19, 0x4d, 0x73, 0x1b, 0x49,
0x75, 0x47, 0x52, 0x2c, 0xe9, 0x49, 0x96, 0x95, 0x8e, 0x77, 0xa3, 0xd8, 0x4e, 0xc5, 0x99, 0x90,
0xda, 0x50, 0x15, 0xbc, 0x54, 0x02, 0x2c, 0x6c, 0x36, 0xb5, 0xab, 0xc8, 0x66, 0xe3, 0x7c, 0x38,
0xae, 0xb6, 0x9d, 0x00, 0x45, 0xd5, 0x54, 0x7b, 0xa6, 0x63, 0x35, 0x1e, 0xcd, 0x0c, 0xd3, 0x2d,
0x87, 0xe1, 0xc6, 0x85, 0x1f, 0xc0, 0x85, 0xeb, 0x9e, 0xe1, 0x46, 0xd5, 0x72, 0xe2, 0x07, 0x70,
0xe3, 0xc0, 0x85, 0x2a, 0xf8, 0x05, 0xfc, 0x0a, 0xaa, 0x5f, 0xf7, 0x48, 0x33, 0xb2, 0x64, 0x9c,
0xe2, 0xc4, 0xc9, 0xfd, 0xde, 0xbc, 0xf7, 0xfa, 0xf5, 0xfb, 0x7e, 0x32, 0x2c, 0x27, 0x4c, 0xa4,
0x22, 0x3a, 0xd9, 0x4a, 0xd2, 0x58, 0xc5, 0xa4, 0x81, 0x7f, 0x8e, 0xc7, 0x6f, 0xd7, 0xae, 0xc9,
0x2c, 0xf2, 0x3d, 0xc9, 0x95, 0x12, 0xd1, 0x89, 0x34, 0x9f, 0xd7, 0x5c, 0x96, 0x24, 0xa1, 0xf0,
0x99, 0x12, 0x71, 0xe4, 0x8d, 0xb8, 0x62, 0x01, 0x53, 0xcc, 0x1b, 0x71, 0x29, 0xd9, 0x09, 0x37,
0x34, 0x2e, 0x83, 0xf5, 0x1f, 0x73, 0xe5, 0x0f, 0x45, 0x74, 0xf2, 0x84, 0xf9, 0xa7, 0x3c, 0x38,
0x4a, 0xb6, 0x99, 0x62, 0xdb, 0x5c, 0x31, 0x11, 0x4a, 0x72, 0x0b, 0x5a, 0xc8, 0x14, 0x8d, 0x47,
0xc7, 0x3c, 0xed, 0x39, 0x9b, 0xce, 0xbd, 0x65, 0x0a, 0x1a, 0xb5, 0x87, 0x18, 0x72, 0x1b, 0xda,
0x2a, 0x56, 0x2c, 0xcc, 0x29, 0x2a, 0x48, 0xd1, 0x42, 0x9c, 0x21, 0x71, 0xff, 0x51, 0x83, 0x25,
0x2d, 0x7b, 0x9c, 0x90, 0x55, 0xb8, 0xe2, 0x87, 0xb1, 0x7f, 0x8a, 0x82, 0x6a, 0xd4, 0x00, 0xa4,
0x03, 0x15, 0x11, 0x20, 0x67, 0x93, 0x56, 0x44, 0x40, 0xbe, 0x80, 0x86, 0x1f, 0x47, 0x8a, 0xf9,
0x4a, 0xf6, 0xaa, 0x9b, 0xd5, 0x7b, 0xad, 0x07, 0x77, 0xb6, 0xf2, 0x97, 0x6e, 0x1d, 0x64, 0x91,
0xbf, 0x1b, 0x49, 0xc5, 0xc2, 0x10, 0x1f, 0x36, 0x30, 0x94, 0xaf, 0x1f, 0xd0, 0x09, 0x13, 0xf9,
0x11, 0xb4, 0xfc, 0x78, 0x34, 0x1a, 0x47, 0x42, 0x09, 0x2e, 0x7b, 0x35, 0x94, 0x71, 0xbd, 0x2c,
0x63, 0x60, 0x09, 0x32, 0x5a, 0xa4, 0x25, 0xaf, 0x60, 0x25, 0x17, 0x63, 0x6d, 0xd0, 0xbb, 0xb2,
0xe9, 0xdc, 0x6b, 0x3d, 0xb8, 0x3b, 0x65, 0xbf, 0xc0, 0x60, 0x74, 0x96, 0x9b, 0x1c, 0x01, 0x29,
0xc8, 0xcf, 0x65, 0x2e, 0xbd, 0x8f, 0xcc, 0x39, 0x02, 0xc8, 0x43, 0xa8, 0x27, 0x69, 0xfc, 0x56,
0x84, 0xbc, 0x57, 0x47, 0x59, 0x37, 0xa6, 0xb2, 0x72, 0x19, 0xfb, 0x86, 0x80, 0xe6, 0x94, 0xe4,
0x25, 0x74, 0xec, 0x31, 0xd7, 0xa3, 0xf1, 0x3e, 0x7a, 0xcc, 0x30, 0x93, 0x4f, 0xa0, 0x6e, 0x23,
0xae, 0xd7, 0x44, 0x39, 0x1f, 0x96, 0x4d, 0x7c, 0x60, 0x3e, 0xd2, 0x9c, 0x4a, 0x1b, 0x37, 0x0f,
0xd1, 0x5c, 0x01, 0x78, 0x2f, 0xe3, 0xce, 0x70, 0xbb, 0x7f, 0xa9, 0x41, 0xfb, 0xe5, 0x38, 0x54,
0xa2, 0xef, 0xfb, 0xf1, 0x38, 0x52, 0x84, 0x40, 0x2d, 0x62, 0x23, 0x8e, 0xf1, 0xd5, 0xa4, 0x78,
0x26, 0x1b, 0xd0, 0x54, 0x62, 0xc4, 0xa5, 0x62, 0xa3, 0x04, 0xa3, 0xac, 0x4a, 0xa7, 0x08, 0xfd,
0x55, 0x04, 0x3c, 0x52, 0xc2, 0x8f, 0xa3, 0x5e, 0x15, 0xd9, 0xa6, 0x08, 0xf2, 0x25, 0x80, 0x1f,
0x87, 0x71, 0xea, 0x0d, 0x99, 0x1c, 0xda, 0x40, 0xba, 0x3d, 0x55, 0xb6, 0x78, 0xf7, 0xd6, 0x20,
0x0e, 0xe3, 0x71, 0xfa, 0x94, 0xc9, 0x21, 0x6d, 0x22, 0x93, 0x3e, 0x92, 0x1e, 0xd4, 0x11, 0xd8,
0x0d, 0x30, 0x90, 0xaa, 0x34, 0x07, 0xc9, 0xc7, 0xb0, 0x72, 0xca, 0x33, 0x9f, 0xa5, 0x81, 0x67,
0xd3, 0x1a, 0xc3, 0xa2, 0x49, 0x3b, 0x16, 0xbd, 0x6f, 0xb0, 0xe4, 0x3a, 0xd4, 0x4f, 0x79, 0xe6,
0x8d, 0x45, 0x80, 0xbe, 0x6e, 0xd2, 0xa5, 0x53, 0x9e, 0x1d, 0x89, 0x80, 0x7c, 0x0e, 0x4b, 0x62,
0xc4, 0x4e, 0xb8, 0xf6, 0xa3, 0xd6, 0xec, 0x5b, 0x0b, 0x34, 0xdb, 0xc5, 0xf7, 0xa8, 0x6c, 0x57,
0x13, 0x53, 0xcb, 0xb3, 0xe6, 0x02, 0x4c, 0x55, 0xd6, 0xa9, 0x29, 0xa2, 0x80, 0xff, 0xaa, 0xe7,
0x6c, 0x56, 0xef, 0x55, 0xa9, 0x01, 0xd6, 0xfe, 0xe9, 0xc0, 0x72, 0x89, 0xbb, 0xa8, 0x8c, 0x53,
0x52, 0x26, 0x37, 0x7d, 0xa5, 0x60, 0xfa, 0x1e, 0xd4, 0x13, 0x96, 0x85, 0x31, 0x0b, 0xd0, 0xb4,
0x6d, 0x9a, 0x83, 0xfa, 0xba, 0x77, 0x22, 0x50, 0xda, 0xa6, 0xda, 0x28, 0x06, 0x20, 0x1f, 0xc1,
0xd2, 0x90, 0x8b, 0x93, 0xa1, 0xb2, 0xb6, 0xb2, 0x10, 0x59, 0x83, 0x86, 0x0e, 0x3c, 0x29, 0x7e,
0xcd, 0xd1, 0x46, 0x55, 0x3a, 0x81, 0xc9, 0x1d, 0x58, 0x4e, 0xf1, 0xe4, 0x29, 0x96, 0x9e, 0x70,
0x85, 0x36, 0xaa, 0xd2, 0xb6, 0x41, 0x1e, 0x22, 0x6e, 0x5a, 0x78, 0x1a, 0x85, 0xc2, 0xe3, 0xfe,
0xdd, 0x81, 0x6b, 0x2f, 0x62, 0x9f, 0x85, 0xd6, 0xd2, 0xfb, 0x56, 0xb9, 0xef, 0x43, 0xed, 0x94,
0x67, 0x12, 0x4d, 0x51, 0xf2, 0xf7, 0x1c, 0xe2, 0xad, 0xe7, 0x3c, 0xa3, 0x48, 0x4e, 0x3e, 0x83,
0xf6, 0x48, 0x9b, 0x9d, 0x19, 0xb3, 0xa3, 0x25, 0x5a, 0x0f, 0x3e, 0x9a, 0xef, 0x14, 0x5a, 0xa2,
0xd5, 0x2f, 0x4c, 0x98, 0x94, 0xef, 0xe2, 0x34, 0xb0, 0x51, 0x38, 0x81, 0xd7, 0xbe, 0x03, 0xd5,
0xe7, 0x3c, 0x9b, 0x1b, 0xdb, 0x04, 0x6a, 0xba, 0x18, 0xe3, 0x55, 0x6d, 0x8a, 0x67, 0xf7, 0xb7,
0x0e, 0x74, 0xb5, 0x8e, 0xc5, 0x2a, 0xb9, 0xa0, 0xf2, 0x7e, 0x0c, 0x2b, 0xa2, 0x40, 0xe5, 0x4d,
0xca, 0x70, 0xa7, 0x88, 0xde, 0x0d, 0xb0, 0x0f, 0xf0, 0x33, 0xe1, 0x73, 0x4f, 0x65, 0x09, 0xb7,
0x1a, 0x82, 0x41, 0x1d, 0x66, 0x09, 0x9f, 0x28, 0x57, 0x9b, 0x2a, 0xe7, 0xfe, 0xdb, 0x81, 0xeb,
0x0b, 0xca, 0xf5, 0x25, 0x3b, 0xc1, 0x1d, 0x58, 0xb6, 0x35, 0xc7, 0xc3, 0xa0, 0xb5, 0x17, 0xb7,
0x2d, 0xd2, 0x44, 0xe4, 0x0d, 0x68, 0xf0, 0x48, 0x7a, 0x85, 0xeb, 0xeb, 0x3c, 0x92, 0x7b, 0xda,
0x3c, 0xb7, 0xa1, 0x1d, 0x32, 0xa9, 0xbc, 0x71, 0x12, 0x30, 0xc5, 0x4d, 0x06, 0xd6, 0x68, 0x4b,
0xe3, 0x8e, 0x0c, 0x4a, 0xbf, 0x4c, 0x66, 0x52, 0xf1, 0x91, 0xa7, 0xd8, 0x89, 0x2e, 0xcc, 0x55,
0xfd, 0x32, 0x83, 0x3a, 0x64, 0x27, 0x92, 0xdc, 0x85, 0x4e, 0xa8, 0xdd, 0xee, 0x45, 0xc2, 0x3f,
0xc5, 0x4b, 0x4c, 0x12, 0x2e, 0x23, 0x76, 0xcf, 0x22, 0xdd, 0xdf, 0x2c, 0xc1, 0x8d, 0x85, 0xbd,
0x89, 0x7c, 0x17, 0x56, 0x8b, 0x8a, 0x78, 0xc8, 0x1b, 0x66, 0xf6, 0xf5, 0xa4, 0xa0, 0xd0, 0x0b,
0xf3, 0xe5, 0xff, 0xd8, 0x14, 0xda, 0xb7, 0x2c, 0x08, 0x78, 0x80, 0x5d, 0xa1, 0x41, 0x0d, 0xa0,
0x6b, 0xc1, 0xb1, 0x76, 0x32, 0x0f, 0xb0, 0xe8, 0x37, 0x68, 0x0e, 0x6a, 0xfa, 0xd1, 0x58, 0xeb,
0xd4, 0x32, 0xf4, 0x08, 0x68, 0xfa, 0x94, 0x8f, 0xe2, 0x33, 0x1e, 0xf4, 0xda, 0x86, 0xde, 0x82,
0x64, 0x13, 0xda, 0x43, 0x26, 0x3d, 0x14, 0xeb, 0x8d, 0x65, 0x6f, 0x19, 0x3f, 0xc3, 0x90, 0xc9,
0xbe, 0x46, 0x1d, 0xe9, 0xce, 0x74, 0xed, 0x8c, 0xa7, 0xe2, 0x6d, 0x3e, 0xfc, 0x48, 0xc5, 0xd4,
0x58, 0xf6, 0x3a, 0x58, 0x19, 0x48, 0xf1, 0xd3, 0x01, 0x7e, 0xc1, 0x31, 0x26, 0x1d, 0x4b, 0x95,
0x53, 0xae, 0x20, 0x65, 0x0b, 0x71, 0x96, 0xe4, 0x31, 0xac, 0xdb, 0xde, 0xee, 0xa5, 0xfc, 0x97,
0x63, 0x2e, 0x95, 0xf1, 0x22, 0xb2, 0xf0, 0x5e, 0x17, 0x39, 0x7a, 0x96, 0x84, 0x1a, 0x0a, 0x74,
0xa6, 0xe6, 0xe7, 0x8b, 0xd9, 0x4d, 0x1a, 0x5c, 0x5d, 0xc8, 0x3e, 0xc0, 0xcc, 0xf8, 0x02, 0x36,
0x66, 0xd9, 0xb5, 0x39, 0x14, 0xb7, 0xd7, 0x13, 0xe4, 0xbf, 0x51, 0xe6, 0xa7, 0x48, 0x61, 0xee,
0x5f, 0x2c, 0xc0, 0x28, 0x70, 0x6d, 0xb1, 0x00, 0xa3, 0xc1, 0x6d, 0x68, 0x07, 0x42, 0x26, 0x21,
0xcb, 0x4c, 0x7c, 0xad, 0xa2, 0xeb, 0x5b, 0x16, 0xa7, 0x63, 0xcc, 0x7d, 0x77, 0x3e, 0xdf, 0xf3,
0xc6, 0x3c, 0x3f, 0xdf, 0xcf, 0x05, 0x75, 0x65, 0x4e, 0x50, 0xcf, 0x46, 0x6e, 0xf5, 0x5c, 0xe4,
0xba, 0x4f, 0x60, 0x6d, 0xf6, 0xe2, 0xfd, 0xf1, 0x71, 0x28, 0xfc, 0xc1, 0x90, 0x5d, 0xb2, 0xd6,
0xb8, 0xdf, 0x54, 0x61, 0xb9, 0x34, 0x18, 0xfe, 0x57, 0xbe, 0x36, 0x26, 0xe6, 0x2d, 0x68, 0x25,
0xa9, 0x38, 0x63, 0x8a, 0x7b, 0xa7, 0x3c, 0xb3, 0x7d, 0x0e, 0x2c, 0x4a, 0xd7, 0xed, 0x4d, 0x5d,
0x3b, 0xa5, 0x9f, 0x8a, 0x44, 0xeb, 0x85, 0x79, 0xd9, 0xa6, 0x45, 0x94, 0x6e, 0x7b, 0xbf, 0x88,
0x45, 0x64, 0xb3, 0xb2, 0x41, 0x2d, 0xa4, 0x9b, 0x82, 0x89, 0x55, 0x1e, 0x60, 0xdb, 0x6b, 0xd0,
0x09, 0x3c, 0x4d, 0x9a, 0x7a, 0x31, 0x69, 0x5e, 0x41, 0xd7, 0x7a, 0x57, 0x7a, 0x2a, 0xf6, 0xb4,
0x1c, 0x3b, 0x1b, 0xdc, 0x5d, 0x34, 0xfe, 0x5a, 0xf2, 0xc3, 0xf8, 0x59, 0x2c, 0x22, 0xda, 0x49,
0x4b, 0x30, 0x79, 0x04, 0x8d, 0x7c, 0xe8, 0xb2, 0x43, 0xde, 0xad, 0x05, 0x82, 0xec, 0xb4, 0x27,
0xe9, 0x84, 0x41, 0xcf, 0x56, 0x3c, 0xf2, 0xd3, 0x2c, 0x51, 0x93, 0xa4, 0x9f, 0x22, 0xf4, 0x57,
0x99, 0x70, 0x5f, 0xb1, 0x69, 0xea, 0x4f, 0x11, 0xba, 0x35, 0x59, 0x52, 0x9d, 0xc0, 0xd8, 0x8e,
0xdb, 0x68, 0xb9, 0xce, 0x14, 0xfd, 0x9c, 0x67, 0xd2, 0xfd, 0x9b, 0x03, 0xeb, 0x17, 0xbc, 0xc8,
0xfa, 0xcb, 0x99, 0xf8, 0xeb, 0x26, 0x40, 0x82, 0xb1, 0x81, 0xee, 0x32, 0xfe, 0x6f, 0x1a, 0x8c,
0xf6, 0xd6, 0xc4, 0xe9, 0xd5, 0xa2, 0xd3, 0x2f, 0x28, 0xac, 0xd7, 0xa1, 0xee, 0x0f, 0x99, 0xd2,
0xbd, 0xf3, 0x8a, 0x19, 0x88, 0x34, 0xb8, 0x1b, 0xe8, 0xb8, 0xcd, 0x07, 0xf7, 0x4c, 0x7f, 0x5d,
0x32, 0x8e, 0x9f, 0xe0, 0x76, 0xd1, 0x89, 0x26, 0x7d, 0xeb, 0xe6, 0x32, 0x04, 0xdc, 0xdf, 0x55,
0xa0, 0x3b, 0x1b, 0xce, 0xe4, 0x71, 0x61, 0x29, 0x3a, 0x37, 0x97, 0x2c, 0x68, 0x3c, 0x85, 0x95,
0xe8, 0x2b, 0x68, 0xdb, 0x57, 0x6b, 0xed, 0x64, 0xaf, 0x32, 0x3b, 0x30, 0x2e, 0xce, 0x1f, 0xda,
0x4a, 0x26, 0x67, 0x49, 0x1e, 0x41, 0x3d, 0x9f, 0x6f, 0xaa, 0x18, 0x0f, 0x17, 0xa8, 0x91, 0x8f,
0x3a, 0x39, 0xc7, 0xff, 0xb0, 0x98, 0xb9, 0x9f, 0xc2, 0x0a, 0x7e, 0xd5, 0x0a, 0xd9, 0x3e, 0x70,
0xb9, 0xbc, 0xfe, 0x1c, 0x56, 0x73, 0xc6, 0x97, 0x66, 0xf5, 0x95, 0x94, 0xb3, 0xcb, 0x72, 0x7f,
0x09, 0x1f, 0x69, 0xee, 0xbe, 0xaf, 0xc4, 0x99, 0x50, 0xd9, 0x80, 0x47, 0x8a, 0xa7, 0x17, 0xf0,
0x77, 0xa1, 0x2a, 0x02, 0x63, 0xde, 0x36, 0xd5, 0x47, 0x77, 0xdb, 0xd4, 0xa6, 0xb2, 0x84, 0xbe,
0xef, 0x73, 0x4c, 0x82, 0xcb, 0x4a, 0xd9, 0x31, 0x41, 0x5e, 0x96, 0xb2, 0x2d, 0xe4, 0x48, 0x48,
0xf9, 0x1e, 0x62, 0xbe, 0x76, 0xa0, 0xad, 0xe5, 0x3c, 0x89, 0xe3, 0xd3, 0x11, 0x4b, 0x4f, 0x17,
0x33, 0x8e, 0xd3, 0xd0, 0x9a, 0x41, 0x1f, 0x27, 0xf3, 0x5d, 0xb5, 0x30, 0x7c, 0xae, 0x43, 0x13,
0xab, 0xb6, 0xa7, 0x69, 0x4d, 0x56, 0x34, 0x10, 0x71, 0x94, 0x86, 0xc5, 0xf6, 0x7d, 0xa5, 0xdc,
0xbe, 0x6f, 0x02, 0x04, 0x3c, 0xe4, 0x7a, 0x0c, 0x62, 0x0a, 0xb3, 0xa2, 0x46, 0x9b, 0x16, 0xd3,
0x57, 0xee, 0x33, 0x13, 0xfc, 0x83, 0x90, 0xb3, 0xf4, 0xa9, 0x90, 0x2a, 0x4e, 0xb3, 0x62, 0x8e,
0x39, 0xa5, 0x1c, 0xbb, 0x09, 0xe0, 0x6b, 0x42, 0x23, 0xab, 0x62, 0x64, 0x59, 0x4c, 0x5f, 0xb9,
0x7f, 0x75, 0x80, 0x68, 0x61, 0x76, 0x13, 0xde, 0x17, 0xbe, 0x1a, 0xa7, 0x7c, 0xee, 0x24, 0x5d,
0x58, 0x55, 0x2a, 0x0b, 0x56, 0x95, 0x2a, 0xfe, 0xb6, 0x71, 0x6e, 0x55, 0xa9, 0x21, 0x3a, 0x5f,
0x55, 0xd6, 0xa1, 0x89, 0xfd, 0x0c, 0x77, 0x95, 0x2b, 0xf8, 0x09, 0x77, 0x95, 0x83, 0xb9, 0xbb,
0xca, 0x12, 0x12, 0x2c, 0xd8, 0x55, 0xea, 0xc5, 0x5d, 0x65, 0x08, 0xd7, 0xce, 0xbf, 0x44, 0x2e,
0x5e, 0xc7, 0x7e, 0x08, 0x8d, 0xc4, 0x12, 0xd9, 0x64, 0xdf, 0x28, 0xe7, 0x59, 0x59, 0x12, 0x9d,
0x50, 0xbb, 0x7f, 0xac, 0xc0, 0x55, 0x4d, 0xf0, 0x86, 0x85, 0x21, 0x57, 0x17, 0x37, 0xf0, 0x1e,
0xd4, 0x59, 0x10, 0xa4, 0x5c, 0xca, 0xdc, 0x6a, 0x16, 0xd4, 0xf6, 0x79, 0x87, 0x02, 0xd0, 0x6c,
0x0d, 0x6a, 0x21, 0x6d, 0x7b, 0xed, 0x3b, 0xb4, 0x5a, 0x83, 0xe2, 0x59, 0xe3, 0x70, 0xad, 0x30,
0xf5, 0x13, 0xcf, 0x5a, 0xb2, 0xf6, 0xbd, 0x1e, 0x0a, 0xcc, 0x56, 0x9c, 0x83, 0x9a, 0x3a, 0x61,
0x6a, 0x68, 0x67, 0x4f, 0x3c, 0xeb, 0x5e, 0x32, 0x29, 0xe1, 0xb8, 0xe3, 0xb5, 0x8b, 0x35, 0x3d,
0xf7, 0x77, 0xb3, 0xe0, 0x6f, 0xfd, 0x1e, 0xbd, 0x88, 0x63, 0x5f, 0x6a, 0x52, 0x03, 0xa0, 0x57,
0x45, 0x10, 0xf0, 0xc8, 0x36, 0x24, 0x0b, 0x2d, 0x1e, 0x46, 0xdd, 0x97, 0x26, 0xc2, 0x4a, 0xc6,
0x92, 0xe4, 0x53, 0x68, 0xd8, 0x9a, 0x97, 0x57, 0xeb, 0xf5, 0xb2, 0xf5, 0x4b, 0xf4, 0x74, 0x42,
0xec, 0xfe, 0xd9, 0x31, 0xe1, 0x7f, 0xc0, 0xce, 0x78, 0xd0, 0xb7, 0xb6, 0x2c, 0x58, 0xd9, 0x29,
0x5b, 0x79, 0xde, 0xd2, 0xbd, 0x01, 0xcd, 0xb7, 0xec, 0x2c, 0x1e, 0xa7, 0x42, 0x71, 0x6b, 0xfc,
0x29, 0x42, 0x77, 0x32, 0x7f, 0xc8, 0x04, 0xee, 0x7a, 0x35, 0x74, 0x65, 0x1d, 0xe1, 0xdd, 0xe0,
0x82, 0x94, 0xbd, 0x0d, 0x6d, 0x33, 0x7d, 0x79, 0xc5, 0xc8, 0x6c, 0x19, 0x1c, 0x8e, 0x87, 0xee,
0xef, 0x1d, 0xf8, 0x70, 0xee, 0x3c, 0xb0, 0x20, 0x72, 0x66, 0xbb, 0xa3, 0x79, 0x41, 0xa9, 0x3b,
0xee, 0xc0, 0xad, 0xa1, 0x29, 0x00, 0x1e, 0x4b, 0xfd, 0xa1, 0x38, 0xe3, 0x9e, 0x1c, 0x27, 0x49,
0x9c, 0x2a, 0x8f, 0x47, 0xec, 0x38, 0xb4, 0xb3, 0x60, 0x83, 0x6e, 0x58, 0xb2, 0xbe, 0xa1, 0x3a,
0x30, 0x44, 0x3b, 0x86, 0xc6, 0xfd, 0x93, 0x63, 0x5a, 0xc7, 0xa1, 0x1e, 0xe6, 0xf5, 0x7a, 0xc0,
0xd3, 0x4b, 0xae, 0x9f, 0x8f, 0x61, 0xc9, 0xee, 0x03, 0xfa, 0x9e, 0xce, 0xec, 0x0c, 0x55, 0x10,
0xb8, 0x75, 0x38, 0xdd, 0x14, 0xa8, 0x65, 0x72, 0x3f, 0x83, 0x56, 0x01, 0x4d, 0x5a, 0x50, 0x3f,
0xda, 0x7b, 0xbe, 0xf7, 0xea, 0xcd, 0x5e, 0xf7, 0x03, 0x0d, 0x1c, 0xd2, 0xa3, 0x83, 0xc3, 0x9d,
0xed, 0xae, 0x43, 0xae, 0xc2, 0xf2, 0xd1, 0x1e, 0x82, 0x6f, 0x5e, 0xd1, 0xc3, 0xa7, 0x3f, 0xed,
0x56, 0xdc, 0xaf, 0xab, 0x66, 0x96, 0x7e, 0x5d, 0xd8, 0x55, 0xec, 0x60, 0xb3, 0x40, 0x79, 0x02,
0xb5, 0xb7, 0x69, 0x3c, 0xca, 0x43, 0x41, 0x9f, 0xf5, 0x83, 0x54, 0x6c, 0x6b, 0x76, 0x45, 0xc5,
0x3a, 0x34, 0xfc, 0xa1, 0x8e, 0xbc, 0xe8, 0x24, 0x9f, 0x63, 0xa6, 0x08, 0xed, 0x12, 0x3b, 0xfd,
0x99, 0x72, 0x6a, 0x57, 0xc4, 0x09, 0xae, 0x8f, 0x3f, 0x53, 0xa4, 0x5c, 0x26, 0x71, 0x24, 0xf3,
0xb4, 0x9c, 0xc0, 0xba, 0x16, 0xa7, 0x3c, 0x09, 0x85, 0x61, 0x36, 0x21, 0xd2, 0xb4, 0x98, 0xbe,
0x22, 0x7c, 0xfe, 0x4e, 0xd6, 0x40, 0xcb, 0x7e, 0xaf, 0x6c, 0xd9, 0x39, 0xaf, 0xde, 0x7a, 0x7d,
0x6e, 0x6b, 0x9b, 0xbb, 0xc9, 0x19, 0x1f, 0x36, 0x27, 0x0d, 0xfc, 0x27, 0x40, 0xce, 0x73, 0x9e,
0xf3, 0xc5, 0xfe, 0xce, 0xde, 0xf6, 0xee, 0xde, 0x57, 0x5d, 0x87, 0xb4, 0xa1, 0xd1, 0x1f, 0x0c,
0x76, 0xf6, 0xb5, 0x67, 0x2a, 0x1a, 0xda, 0xde, 0x19, 0xbc, 0xd8, 0xdd, 0xdb, 0xd9, 0xee, 0x56,
0x35, 0x34, 0xe8, 0xef, 0x0d, 0x76, 0x5e, 0xec, 0x6c, 0x77, 0x6b, 0xee, 0xbf, 0x1c, 0xd3, 0xd9,
0x07, 0xa5, 0x95, 0x69, 0x9b, 0xfb, 0x42, 0x2e, 0xfe, 0xc5, 0x65, 0x03, 0x9a, 0xd6, 0x9e, 0xbb,
0x79, 0xa4, 0x4d, 0x11, 0xe4, 0xe7, 0xb0, 0x12, 0x58, 0x7e, 0xaf, 0x14, 0x79, 0x0f, 0x67, 0x67,
0xa4, 0x79, 0x57, 0x6e, 0xe5, 0x07, 0x6b, 0x9e, 0x4e, 0x50, 0x82, 0xdd, 0xfb, 0xd0, 0x29, 0x53,
0x94, 0x1e, 0xfb, 0x41, 0xe9, 0xb1, 0x8e, 0xfb, 0x8d, 0x03, 0x2b, 0x33, 0xbf, 0x24, 0x2f, 0xee,
0x36, 0xb3, 0xcb, 0x61, 0xe5, 0xdc, 0x72, 0x48, 0xee, 0x03, 0x29, 0x92, 0x78, 0xc5, 0x29, 0xbb,
0x5b, 0x20, 0x34, 0xdb, 0x66, 0xb1, 0x7d, 0xd5, 0xde, 0xab, 0x7d, 0x49, 0x00, 0xca, 0xde, 0xd9,
0x51, 0xaf, 0xd8, 0xd6, 0x9d, 0x72, 0x5b, 0x7f, 0x0e, 0x2d, 0xfb, 0xaf, 0x90, 0x43, 0xdd, 0x7b,
0x2a, 0x68, 0xe7, 0x6f, 0x4f, 0x2f, 0xe9, 0x4f, 0xff, 0x79, 0xf2, 0xd2, 0xfe, 0xef, 0xc4, 0x0a,
0xdd, 0xd2, 0x0c, 0xb4, 0xc8, 0xed, 0xfe, 0xc1, 0x81, 0x8e, 0xd6, 0xaa, 0x70, 0xf3, 0x0f, 0xa0,
0x95, 0x4e, 0xa0, 0xbc, 0x0b, 0xac, 0x4e, 0xe5, 0x4f, 0x49, 0x69, 0x91, 0x90, 0x3c, 0x80, 0x55,
0x39, 0x3e, 0xce, 0x3b, 0xc9, 0x33, 0x19, 0x47, 0x4f, 0x32, 0xc5, 0xf3, 0xfe, 0x3a, 0xf7, 0x1b,
0xb9, 0x0f, 0x57, 0xf3, 0xa5, 0x6b, 0xca, 0x60, 0x36, 0xd1, 0xf3, 0x1f, 0x9e, 0x2c, 0xff, 0xac,
0xb5, 0xf5, 0xc9, 0xa3, 0x5c, 0x91, 0xe3, 0x25, 0x3c, 0x3d, 0xfc, 0x4f, 0x00, 0x00, 0x00, 0xff,
0xff, 0xa8, 0x44, 0x31, 0x9e, 0x5d, 0x1a, 0x00, 0x00,
// 2596 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x39, 0x4d, 0x73, 0x1b, 0xc7,
0xb1, 0x5e, 0x00, 0xc4, 0x47, 0x03, 0x04, 0xa1, 0x11, 0x2d, 0x41, 0x14, 0x5d, 0x92, 0xd6, 0x76,
0x59, 0xaf, 0xca, 0x8f, 0x7e, 0x4f, 0x4e, 0xe2, 0xc4, 0x1f, 0x65, 0x43, 0x00, 0x62, 0xd1, 0x14,
0x41, 0xd6, 0x90, 0x90, 0x63, 0x57, 0xaa, 0xb6, 0x86, 0xbb, 0x23, 0x62, 0xc3, 0xc5, 0xee, 0x66,
0x67, 0x40, 0x05, 0xb9, 0xe5, 0x92, 0x1f, 0x90, 0x4b, 0x72, 0xf4, 0x39, 0xb9, 0xa5, 0xca, 0x39,
0xe5, 0x90, 0x63, 0x6e, 0x39, 0xe4, 0x92, 0xaa, 0xe4, 0x17, 0xe4, 0x57, 0xa4, 0xa6, 0x67, 0x16,
0xbb, 0x0b, 0x02, 0x8c, 0x54, 0x39, 0xe5, 0xc4, 0xe9, 0xde, 0xee, 0x9e, 0x9e, 0xfe, 0x6e, 0x10,
0x36, 0x63, 0xe6, 0x27, 0x7e, 0x78, 0xbe, 0x17, 0x27, 0x91, 0x8c, 0x48, 0x1d, 0xff, 0x9c, 0xcd,
0x9e, 0xef, 0xdc, 0x14, 0xf3, 0xd0, 0x75, 0x04, 0x97, 0xd2, 0x0f, 0xcf, 0x85, 0xfe, 0xbc, 0x63,
0xb3, 0x38, 0x0e, 0x7c, 0x97, 0x49, 0x3f, 0x0a, 0x9d, 0x29, 0x97, 0xcc, 0x63, 0x92, 0x39, 0x53,
0x2e, 0x04, 0x3b, 0xe7, 0x9a, 0xc6, 0x66, 0x70, 0xf7, 0x87, 0x5c, 0xba, 0x13, 0x3f, 0x3c, 0x7f,
0xcc, 0xdc, 0x0b, 0xee, 0x8d, 0xe3, 0x01, 0x93, 0x6c, 0xc0, 0x25, 0xf3, 0x03, 0x41, 0xee, 0x41,
0x13, 0x99, 0xc2, 0xd9, 0xf4, 0x8c, 0x27, 0x5d, 0xeb, 0xbe, 0xf5, 0x70, 0x93, 0x82, 0x42, 0x8d,
0x10, 0x43, 0x1e, 0x40, 0x4b, 0x46, 0x92, 0x05, 0x29, 0x45, 0x09, 0x29, 0x9a, 0x88, 0xd3, 0x24,
0xf6, 0xdf, 0x2a, 0x50, 0x55, 0xb2, 0x67, 0x31, 0xd9, 0x86, 0x0d, 0x37, 0x88, 0xdc, 0x0b, 0x14,
0x54, 0xa1, 0x1a, 0x20, 0x6d, 0x28, 0xf9, 0x1e, 0x72, 0x36, 0x68, 0xc9, 0xf7, 0xc8, 0xa7, 0x50,
0x77, 0xa3, 0x50, 0x32, 0x57, 0x8a, 0x6e, 0xf9, 0x7e, 0xf9, 0x61, 0xf3, 0xd1, 0x9b, 0x7b, 0xe9,
0x4b, 0xf7, 0x4e, 0xe6, 0xa1, 0xbb, 0x1f, 0x0a, 0xc9, 0x82, 0x00, 0x1f, 0xd6, 0xd7, 0x94, 0xcf,
0x1e, 0xd1, 0x05, 0x13, 0xf9, 0x01, 0x34, 0xdd, 0x68, 0x3a, 0x9d, 0x85, 0xbe, 0xf4, 0xb9, 0xe8,
0x56, 0x50, 0xc6, 0xed, 0xa2, 0x8c, 0xbe, 0x21, 0x98, 0xd3, 0x3c, 0x2d, 0x39, 0x82, 0xad, 0x54,
0x8c, 0xb1, 0x41, 0x77, 0xe3, 0xbe, 0xf5, 0xb0, 0xf9, 0xe8, 0xed, 0x8c, 0xfd, 0x1a, 0x83, 0xd1,
0x65, 0x6e, 0x32, 0x06, 0x92, 0x93, 0x9f, 0xca, 0xac, 0xbe, 0x8a, 0xcc, 0x15, 0x02, 0xc8, 0xfb,
0x50, 0x8b, 0x93, 0xe8, 0xb9, 0x1f, 0xf0, 0x6e, 0x0d, 0x65, 0xdd, 0xc9, 0x64, 0xa5, 0x32, 0x8e,
0x35, 0x01, 0x4d, 0x29, 0xc9, 0x21, 0xb4, 0xcd, 0x31, 0xd5, 0xa3, 0xfe, 0x2a, 0x7a, 0x2c, 0x31,
0x93, 0xf7, 0xa0, 0x66, 0x22, 0xae, 0xdb, 0x40, 0x39, 0xaf, 0x17, 0x4d, 0x7c, 0xa2, 0x3f, 0xd2,
0x94, 0x4a, 0x19, 0x37, 0x0d, 0xd1, 0x54, 0x01, 0x78, 0x25, 0xe3, 0x2e, 0x71, 0xdb, 0x7f, 0xac,
0x40, 0xeb, 0x70, 0x16, 0x48, 0xbf, 0xe7, 0xba, 0xd1, 0x2c, 0x94, 0x84, 0x40, 0x25, 0x64, 0x53,
0x8e, 0xf1, 0xd5, 0xa0, 0x78, 0x26, 0xbb, 0xd0, 0x90, 0xfe, 0x94, 0x0b, 0xc9, 0xa6, 0x31, 0x46,
0x59, 0x99, 0x66, 0x08, 0xf5, 0xd5, 0xf7, 0x78, 0x28, 0x7d, 0x37, 0x0a, 0xbb, 0x65, 0x64, 0xcb,
0x10, 0xe4, 0x33, 0x00, 0x37, 0x0a, 0xa2, 0xc4, 0x99, 0x30, 0x31, 0x31, 0x81, 0xf4, 0x20, 0x53,
0x36, 0x7f, 0xf7, 0x5e, 0x3f, 0x0a, 0xa2, 0x59, 0xf2, 0x84, 0x89, 0x09, 0x6d, 0x20, 0x93, 0x3a,
0x92, 0x2e, 0xd4, 0x10, 0xd8, 0xf7, 0x30, 0x90, 0xca, 0x34, 0x05, 0xc9, 0x3b, 0xb0, 0x75, 0xc1,
0xe7, 0x2e, 0x4b, 0x3c, 0xc7, 0xa4, 0x35, 0x86, 0x45, 0x83, 0xb6, 0x0d, 0xfa, 0x58, 0x63, 0xc9,
0x6d, 0xa8, 0x5d, 0xf0, 0xb9, 0x33, 0xf3, 0x3d, 0xf4, 0x75, 0x83, 0x56, 0x2f, 0xf8, 0x7c, 0xec,
0x7b, 0xe4, 0x63, 0xa8, 0xfa, 0x53, 0x76, 0xce, 0x95, 0x1f, 0x95, 0x66, 0x6f, 0xad, 0xd1, 0x6c,
0x1f, 0xdf, 0x23, 0xe7, 0xfb, 0x8a, 0x98, 0x1a, 0x9e, 0x1d, 0x1b, 0x20, 0x53, 0x59, 0xa5, 0xa6,
0x1f, 0x7a, 0xfc, 0x67, 0x5d, 0xeb, 0x7e, 0xf9, 0x61, 0x99, 0x6a, 0x60, 0xe7, 0xef, 0x16, 0x6c,
0x16, 0xb8, 0xf3, 0xca, 0x58, 0x05, 0x65, 0x52, 0xd3, 0x97, 0x72, 0xa6, 0xef, 0x42, 0x2d, 0x66,
0xf3, 0x20, 0x62, 0x1e, 0x9a, 0xb6, 0x45, 0x53, 0x50, 0x5d, 0xf7, 0xc2, 0xf7, 0xa4, 0xb2, 0xa9,
0x32, 0x8a, 0x06, 0xc8, 0x2d, 0xa8, 0x4e, 0xb8, 0x7f, 0x3e, 0x91, 0xc6, 0x56, 0x06, 0x22, 0x3b,
0x50, 0x57, 0x81, 0x27, 0xfc, 0x9f, 0x73, 0xb4, 0x51, 0x99, 0x2e, 0x60, 0xf2, 0x26, 0x6c, 0x26,
0x78, 0x72, 0x24, 0x4b, 0xce, 0xb9, 0x44, 0x1b, 0x95, 0x69, 0x4b, 0x23, 0x4f, 0x11, 0x97, 0x15,
0x9e, 0x7a, 0xae, 0xf0, 0xd8, 0x7f, 0xb5, 0xe0, 0xe6, 0xd3, 0xc8, 0x65, 0x81, 0xb1, 0xf4, 0xb1,
0x51, 0xee, 0xbb, 0x50, 0xb9, 0xe0, 0x73, 0x81, 0xa6, 0x28, 0xf8, 0x7b, 0x05, 0xf1, 0xde, 0x01,
0x9f, 0x53, 0x24, 0x27, 0x1f, 0x42, 0x6b, 0xaa, 0xcc, 0xce, 0xb4, 0xd9, 0xd1, 0x12, 0xcd, 0x47,
0xb7, 0x56, 0x3b, 0x85, 0x16, 0x68, 0xd5, 0x0b, 0x63, 0x26, 0xc4, 0x8b, 0x28, 0xf1, 0x4c, 0x14,
0x2e, 0xe0, 0x9d, 0xff, 0x85, 0xf2, 0x01, 0x9f, 0xaf, 0x8c, 0x6d, 0x02, 0x15, 0x55, 0x8c, 0xf1,
0xaa, 0x16, 0xc5, 0xb3, 0xfd, 0x4b, 0x0b, 0x3a, 0x4a, 0xc7, 0x7c, 0x95, 0x5c, 0x53, 0x79, 0xdf,
0x81, 0x2d, 0x3f, 0x47, 0xe5, 0x2c, 0xca, 0x70, 0x3b, 0x8f, 0xde, 0xf7, 0xb0, 0x0f, 0xf0, 0x4b,
0xdf, 0xe5, 0x8e, 0x9c, 0xc7, 0xdc, 0x68, 0x08, 0x1a, 0x75, 0x3a, 0x8f, 0xf9, 0x42, 0xb9, 0x4a,
0xa6, 0x9c, 0xfd, 0x4f, 0x0b, 0x6e, 0xaf, 0x29, 0xd7, 0x2f, 0xd9, 0x09, 0xde, 0x84, 0x4d, 0x53,
0x73, 0x1c, 0x0c, 0x5a, 0x73, 0x71, 0xcb, 0x20, 0x75, 0x44, 0xde, 0x81, 0x3a, 0x0f, 0x85, 0x93,
0xbb, 0xbe, 0xc6, 0x43, 0x31, 0x52, 0xe6, 0x79, 0x00, 0xad, 0x80, 0x09, 0xe9, 0xcc, 0x62, 0x8f,
0x49, 0xae, 0x33, 0xb0, 0x42, 0x9b, 0x0a, 0x37, 0xd6, 0x28, 0xf5, 0x32, 0x31, 0x17, 0x92, 0x4f,
0x1d, 0xc9, 0xce, 0x55, 0x61, 0x2e, 0xab, 0x97, 0x69, 0xd4, 0x29, 0x3b, 0x17, 0xe4, 0x6d, 0x68,
0x07, 0xca, 0xed, 0x4e, 0xe8, 0xbb, 0x17, 0x78, 0x89, 0x4e, 0xc2, 0x4d, 0xc4, 0x8e, 0x0c, 0xd2,
0xfe, 0x45, 0x15, 0xee, 0xac, 0xed, 0x4d, 0xe4, 0xff, 0x60, 0x3b, 0xaf, 0x88, 0x83, 0xbc, 0xc1,
0xdc, 0xbc, 0x9e, 0xe4, 0x14, 0x7a, 0xaa, 0xbf, 0xfc, 0x17, 0x9b, 0x42, 0xf9, 0x96, 0x79, 0x1e,
0xf7, 0xb0, 0x2b, 0xd4, 0xa9, 0x06, 0x54, 0x2d, 0x38, 0x53, 0x4e, 0xe6, 0x1e, 0x16, 0xfd, 0x3a,
0x4d, 0x41, 0x45, 0x3f, 0x9d, 0x29, 0x9d, 0x9a, 0x9a, 0x1e, 0x01, 0x45, 0x9f, 0xf0, 0x69, 0x74,
0xc9, 0xbd, 0x6e, 0x4b, 0xd3, 0x1b, 0x90, 0xdc, 0x87, 0xd6, 0x84, 0x09, 0x07, 0xc5, 0x3a, 0x33,
0xd1, 0xdd, 0xc4, 0xcf, 0x30, 0x61, 0xa2, 0xa7, 0x50, 0x63, 0xd5, 0x99, 0x6e, 0x5e, 0xf2, 0xc4,
0x7f, 0x9e, 0x0e, 0x3f, 0x42, 0x32, 0x39, 0x13, 0xdd, 0x36, 0x56, 0x06, 0x92, 0xff, 0x74, 0x82,
0x5f, 0x70, 0x8c, 0x49, 0x66, 0x42, 0xa6, 0x94, 0x5b, 0x48, 0xd9, 0x44, 0x9c, 0x21, 0xf9, 0x04,
0xee, 0x9a, 0xde, 0xee, 0x24, 0xfc, 0xa7, 0x33, 0x2e, 0xa4, 0xf6, 0x22, 0xb2, 0xf0, 0x6e, 0x07,
0x39, 0xba, 0x86, 0x84, 0x6a, 0x0a, 0x74, 0xa6, 0xe2, 0xe7, 0xeb, 0xd9, 0x75, 0x1a, 0xdc, 0x58,
0xcb, 0xde, 0xc7, 0xcc, 0xf8, 0x14, 0x76, 0x97, 0xd9, 0x95, 0x39, 0x24, 0x37, 0xd7, 0x13, 0xe4,
0xbf, 0x53, 0xe4, 0xa7, 0x48, 0xa1, 0xef, 0x5f, 0x2f, 0x40, 0x2b, 0x70, 0x73, 0xbd, 0x00, 0xad,
0xc1, 0x03, 0x68, 0x79, 0xbe, 0x88, 0x03, 0x36, 0xd7, 0xf1, 0xb5, 0x8d, 0xae, 0x6f, 0x1a, 0x9c,
0x8a, 0x31, 0xfb, 0xc5, 0xd5, 0x7c, 0x4f, 0x1b, 0xf3, 0xea, 0x7c, 0xbf, 0x12, 0xd4, 0xa5, 0x15,
0x41, 0xbd, 0x1c, 0xb9, 0xe5, 0x2b, 0x91, 0x6b, 0x3f, 0x86, 0x9d, 0xe5, 0x8b, 0x8f, 0x67, 0x67,
0x81, 0xef, 0xf6, 0x27, 0xec, 0x25, 0x6b, 0x8d, 0xfd, 0x6d, 0x19, 0x36, 0x0b, 0x83, 0xe1, 0xbf,
0xe5, 0x6b, 0x61, 0x62, 0xde, 0x83, 0x66, 0x9c, 0xf8, 0x97, 0x4c, 0x72, 0xe7, 0x82, 0xcf, 0x4d,
0x9f, 0x03, 0x83, 0x52, 0x75, 0xfb, 0xbe, 0xaa, 0x9d, 0xc2, 0x4d, 0xfc, 0x58, 0xe9, 0x85, 0x79,
0xd9, 0xa2, 0x79, 0x94, 0x6a, 0x7b, 0x3f, 0x89, 0xfc, 0xd0, 0x64, 0x65, 0x9d, 0x1a, 0x48, 0x35,
0x05, 0x1d, 0xab, 0xdc, 0xc3, 0xb6, 0x57, 0xa7, 0x0b, 0x38, 0x4b, 0x9a, 0x5a, 0x3e, 0x69, 0x8e,
0xa0, 0x63, 0xbc, 0x2b, 0x1c, 0x19, 0x39, 0x4a, 0x8e, 0x99, 0x0d, 0xde, 0x5e, 0x37, 0xfe, 0x1a,
0xf2, 0xd3, 0xe8, 0x8b, 0xc8, 0x0f, 0x69, 0x3b, 0x29, 0xc0, 0xe4, 0x23, 0xa8, 0xa7, 0x43, 0x97,
0x19, 0xf2, 0xee, 0xad, 0x11, 0x64, 0xa6, 0x3d, 0x41, 0x17, 0x0c, 0x6a, 0xb6, 0xe2, 0xa1, 0x9b,
0xcc, 0x63, 0xb9, 0x48, 0xfa, 0x0c, 0xa1, 0xbe, 0x8a, 0x98, 0xbb, 0x92, 0x65, 0xa9, 0x9f, 0x21,
0x54, 0x6b, 0x32, 0xa4, 0x2a, 0x81, 0xb1, 0x1d, 0xb7, 0xd0, 0x72, 0xed, 0x0c, 0x7d, 0xc0, 0xe7,
0xc2, 0xfe, 0x8b, 0x05, 0x77, 0xaf, 0x79, 0x91, 0xf1, 0x97, 0xb5, 0xf0, 0xd7, 0x1b, 0x00, 0x31,
0xc6, 0x06, 0xba, 0x4b, 0xfb, 0xbf, 0xa1, 0x31, 0xca, 0x5b, 0x0b, 0xa7, 0x97, 0xf3, 0x4e, 0xbf,
0xa6, 0xb0, 0xde, 0x86, 0x9a, 0x3b, 0x61, 0x52, 0xf5, 0xce, 0x0d, 0x3d, 0x10, 0x29, 0x70, 0xdf,
0x53, 0x71, 0x9b, 0x0e, 0xee, 0x73, 0xf5, 0xb5, 0xaa, 0x1d, 0xbf, 0xc0, 0xed, 0xa3, 0x13, 0x75,
0xfa, 0xd6, 0xf4, 0x65, 0x08, 0xd8, 0xbf, 0x2a, 0x41, 0x67, 0x39, 0x9c, 0xc9, 0x27, 0xb9, 0xa5,
0xe8, 0xca, 0x5c, 0xb2, 0xa6, 0xf1, 0xe4, 0x56, 0xa2, 0xcf, 0xa1, 0x65, 0x5e, 0xad, 0xb4, 0x13,
0xdd, 0xd2, 0xf2, 0xc0, 0xb8, 0x3e, 0x7f, 0x68, 0x33, 0x5e, 0x9c, 0x05, 0xf9, 0x08, 0x6a, 0xe9,
0x7c, 0x53, 0xc6, 0x78, 0xb8, 0x46, 0x8d, 0x74, 0xd4, 0x49, 0x39, 0xfe, 0x83, 0xc5, 0xcc, 0xfe,
0x00, 0xb6, 0xf0, 0xab, 0x52, 0xc8, 0xf4, 0x81, 0x97, 0xcb, 0xeb, 0x8f, 0x61, 0x3b, 0x65, 0x3c,
0xd4, 0xab, 0xaf, 0xa0, 0x9c, 0xbd, 0x2c, 0xf7, 0x67, 0x70, 0x4b, 0x71, 0xf7, 0x5c, 0xe9, 0x5f,
0xfa, 0x72, 0xde, 0xe7, 0xa1, 0xe4, 0xc9, 0x35, 0xfc, 0x1d, 0x28, 0xfb, 0x9e, 0x36, 0x6f, 0x8b,
0xaa, 0xa3, 0x3d, 0xd0, 0xb5, 0xa9, 0x28, 0xa1, 0xe7, 0xba, 0x1c, 0x93, 0xe0, 0x65, 0xa5, 0x0c,
0x75, 0x90, 0x17, 0xa5, 0x0c, 0x7c, 0x31, 0xf5, 0x85, 0x78, 0x05, 0x31, 0xdf, 0x58, 0xd0, 0x52,
0x72, 0x1e, 0x47, 0xd1, 0xc5, 0x94, 0x25, 0x17, 0xeb, 0x19, 0x67, 0x49, 0x60, 0xcc, 0xa0, 0x8e,
0x8b, 0xf9, 0xae, 0x9c, 0x1b, 0x3e, 0xef, 0x42, 0x03, 0xab, 0xb6, 0xa3, 0x68, 0x75, 0x56, 0xd4,
0x11, 0x31, 0x4e, 0x82, 0x7c, 0xfb, 0xde, 0x28, 0xb6, 0xef, 0x37, 0x00, 0x3c, 0x1e, 0x70, 0x35,
0x06, 0x31, 0x89, 0x59, 0x51, 0xa1, 0x0d, 0x83, 0xe9, 0x49, 0xfb, 0x0b, 0x1d, 0xfc, 0xfd, 0x80,
0xb3, 0xe4, 0x89, 0x2f, 0x64, 0x94, 0xcc, 0xf3, 0x39, 0x66, 0x15, 0x72, 0xec, 0x0d, 0x00, 0x57,
0x11, 0x6a, 0x59, 0x25, 0x2d, 0xcb, 0x60, 0x7a, 0xd2, 0xfe, 0xb3, 0x05, 0x44, 0x09, 0x33, 0x9b,
0xf0, 0xb1, 0xef, 0xca, 0x59, 0xc2, 0x57, 0x4e, 0xd2, 0xb9, 0x55, 0xa5, 0xb4, 0x66, 0x55, 0x29,
0xe3, 0x6f, 0x1b, 0x57, 0x56, 0x95, 0x0a, 0xa2, 0xd3, 0x55, 0xe5, 0x2e, 0x34, 0xb0, 0x9f, 0xe1,
0xae, 0xb2, 0x81, 0x9f, 0x70, 0x57, 0x39, 0x59, 0xb9, 0xab, 0x54, 0x91, 0x60, 0xcd, 0xae, 0x52,
0xcb, 0xef, 0x2a, 0x13, 0xb8, 0x79, 0xf5, 0x25, 0x62, 0xfd, 0x3a, 0xf6, 0x7d, 0xa8, 0xc7, 0x86,
0xc8, 0x24, 0xfb, 0x6e, 0x31, 0xcf, 0x8a, 0x92, 0xe8, 0x82, 0xda, 0xfe, 0x5d, 0x09, 0x6e, 0x28,
0x82, 0x2f, 0x59, 0x10, 0x70, 0x79, 0x7d, 0x03, 0xef, 0x42, 0x8d, 0x79, 0x5e, 0xc2, 0x85, 0x48,
0xad, 0x66, 0x40, 0x65, 0x9f, 0x17, 0x28, 0x00, 0xcd, 0x56, 0xa7, 0x06, 0x52, 0xb6, 0x57, 0xbe,
0x43, 0xab, 0xd5, 0x29, 0x9e, 0x15, 0x0e, 0xd7, 0x0a, 0x5d, 0x3f, 0xf1, 0xac, 0x24, 0x2b, 0xdf,
0xab, 0xa1, 0x40, 0x6f, 0xc5, 0x29, 0xa8, 0xa8, 0x63, 0x26, 0x27, 0x66, 0xf6, 0xc4, 0xb3, 0xea,
0x25, 0x8b, 0x12, 0x8e, 0x3b, 0x5e, 0x2b, 0x5f, 0xd3, 0x53, 0x7f, 0x37, 0x72, 0xfe, 0x56, 0xef,
0x51, 0x8b, 0x38, 0xf6, 0xa5, 0x06, 0xd5, 0x00, 0x7a, 0xd5, 0xf7, 0x3c, 0x1e, 0x9a, 0x86, 0x64,
0xa0, 0xf5, 0xc3, 0xa8, 0x7d, 0xa8, 0x23, 0xac, 0x60, 0x2c, 0x41, 0x3e, 0x80, 0xba, 0xa9, 0x79,
0x69, 0xb5, 0xbe, 0x5b, 0xb4, 0x7e, 0x81, 0x9e, 0x2e, 0x88, 0xed, 0x3f, 0x58, 0x3a, 0xfc, 0x4f,
0xd8, 0x25, 0xf7, 0x7a, 0xc6, 0x96, 0x39, 0x2b, 0x5b, 0x45, 0x2b, 0xaf, 0x5a, 0xba, 0x77, 0xa1,
0xf1, 0x9c, 0x5d, 0x46, 0xb3, 0xc4, 0x97, 0xdc, 0x18, 0x3f, 0x43, 0xa8, 0x4e, 0xe6, 0x4e, 0x98,
0x8f, 0xbb, 0x5e, 0x05, 0x5d, 0x59, 0x43, 0x78, 0xdf, 0xbb, 0x26, 0x65, 0x1f, 0x40, 0x4b, 0x4f,
0x5f, 0x4e, 0x3e, 0x32, 0x9b, 0x1a, 0x87, 0xe3, 0xa1, 0xfd, 0x6b, 0x0b, 0x5e, 0x5f, 0x39, 0x0f,
0xac, 0x89, 0x9c, 0xe5, 0xee, 0xa8, 0x5f, 0x50, 0xe8, 0x8e, 0x43, 0xb8, 0x37, 0xd1, 0x05, 0xc0,
0x61, 0x89, 0x3b, 0xf1, 0x2f, 0xb9, 0x23, 0x66, 0x71, 0x1c, 0x25, 0xd2, 0xe1, 0x21, 0x3b, 0x0b,
0xcc, 0x2c, 0x58, 0xa7, 0xbb, 0x86, 0xac, 0xa7, 0xa9, 0x4e, 0x34, 0xd1, 0x50, 0xd3, 0xd8, 0xbf,
0xb7, 0x74, 0xeb, 0x38, 0x55, 0xc3, 0xbc, 0x5a, 0x0f, 0x78, 0xf2, 0x92, 0xeb, 0xe7, 0x27, 0x50,
0x35, 0xfb, 0x80, 0xba, 0xa7, 0xbd, 0x3c, 0x43, 0xe5, 0x04, 0xee, 0x9d, 0x66, 0x9b, 0x02, 0x35,
0x4c, 0xf6, 0x87, 0xd0, 0xcc, 0xa1, 0x49, 0x13, 0x6a, 0xe3, 0xd1, 0xc1, 0xe8, 0xe8, 0xcb, 0x51,
0xe7, 0x35, 0x05, 0x9c, 0xd2, 0xf1, 0xc9, 0xe9, 0x70, 0xd0, 0xb1, 0xc8, 0x0d, 0xd8, 0x1c, 0x8f,
0x10, 0xfc, 0xf2, 0x88, 0x9e, 0x3e, 0xf9, 0xaa, 0x53, 0xb2, 0xbf, 0x29, 0xeb, 0x59, 0xfa, 0x59,
0x6e, 0x57, 0x31, 0x83, 0xcd, 0x1a, 0xe5, 0x09, 0x54, 0x9e, 0x27, 0xd1, 0x34, 0x0d, 0x05, 0x75,
0x56, 0x0f, 0x92, 0x91, 0xa9, 0xd9, 0x25, 0x19, 0xa9, 0xd0, 0x70, 0x27, 0x2a, 0xf2, 0xc2, 0xf3,
0x74, 0x8e, 0xc9, 0x10, 0xca, 0x25, 0x66, 0xfa, 0xd3, 0xe5, 0xd4, 0xac, 0x88, 0x0b, 0x5c, 0x0f,
0x7f, 0xa6, 0x48, 0xb8, 0x88, 0xa3, 0x50, 0xa4, 0x69, 0xb9, 0x80, 0x55, 0x2d, 0x4e, 0x78, 0x1c,
0xf8, 0x9a, 0x59, 0x87, 0x48, 0xc3, 0x60, 0x7a, 0x92, 0xf0, 0xd5, 0x3b, 0x59, 0x1d, 0x2d, 0xfb,
0x9d, 0xa2, 0x65, 0x57, 0xbc, 0x7a, 0xef, 0xd9, 0x95, 0xad, 0x6d, 0xe5, 0x26, 0xa7, 0x7d, 0xd8,
0x58, 0x34, 0xf0, 0x1f, 0x01, 0xb9, 0xca, 0x79, 0xc5, 0x17, 0xc7, 0xc3, 0xd1, 0x60, 0x7f, 0xf4,
0x79, 0xc7, 0x22, 0x2d, 0xa8, 0xf7, 0xfa, 0xfd, 0xe1, 0xb1, 0xf2, 0x4c, 0x49, 0x41, 0x83, 0x61,
0xff, 0xe9, 0xfe, 0x68, 0x38, 0xe8, 0x94, 0x15, 0xd4, 0xef, 0x8d, 0xfa, 0xc3, 0xa7, 0xc3, 0x41,
0xa7, 0x62, 0xff, 0xc3, 0xd2, 0x9d, 0xbd, 0x5f, 0x58, 0x99, 0x06, 0xdc, 0xf5, 0xc5, 0xfa, 0x5f,
0x5c, 0x76, 0xa1, 0x61, 0xec, 0xb9, 0x9f, 0x46, 0x5a, 0x86, 0x20, 0x3f, 0x86, 0x2d, 0xcf, 0xf0,
0x3b, 0x85, 0xc8, 0x7b, 0x7f, 0x79, 0x46, 0x5a, 0x75, 0xe5, 0x5e, 0x7a, 0x30, 0xe6, 0x69, 0x7b,
0x05, 0xd8, 0x7e, 0x17, 0xda, 0x45, 0x8a, 0xc2, 0x63, 0x5f, 0x2b, 0x3c, 0xd6, 0xb2, 0xbf, 0xb5,
0x60, 0x6b, 0xe9, 0x97, 0xe4, 0xf5, 0xdd, 0x66, 0x79, 0x39, 0x2c, 0x5d, 0x59, 0x0e, 0xc9, 0xbb,
0x40, 0xf2, 0x24, 0x4e, 0x7e, 0xca, 0xee, 0xe4, 0x08, 0xf5, 0xb6, 0x99, 0x6f, 0x5f, 0x95, 0x57,
0x6a, 0x5f, 0x02, 0x80, 0xb2, 0x17, 0x66, 0xd4, 0xcb, 0xb7, 0x75, 0xab, 0xd8, 0xd6, 0x0f, 0xa0,
0x69, 0xfe, 0x15, 0x72, 0xaa, 0x7a, 0x4f, 0x09, 0xed, 0xfc, 0x3f, 0xd9, 0x25, 0xbd, 0xec, 0x9f,
0x27, 0x87, 0xe6, 0x7f, 0x27, 0x46, 0xe8, 0x9e, 0x62, 0xa0, 0x79, 0x6e, 0xfb, 0xb7, 0x16, 0xb4,
0x95, 0x56, 0xb9, 0x9b, 0xbf, 0x07, 0xcd, 0x64, 0x01, 0xa5, 0x5d, 0x60, 0x3b, 0x93, 0x9f, 0x91,
0xd2, 0x3c, 0x21, 0x79, 0x04, 0xdb, 0x62, 0x76, 0x96, 0x76, 0x92, 0x2f, 0x44, 0x14, 0x3e, 0x9e,
0x4b, 0x9e, 0xf6, 0xd7, 0x95, 0xdf, 0xc8, 0xbb, 0x70, 0x23, 0x5d, 0xba, 0x32, 0x06, 0xbd, 0x89,
0x5e, 0xfd, 0x60, 0xff, 0xc6, 0x82, 0xa6, 0x52, 0xf6, 0x40, 0xff, 0xcc, 0x8c, 0xd3, 0xde, 0xc2,
0xa3, 0xea, 0xb8, 0xb2, 0xad, 0xdc, 0x82, 0xaa, 0xf9, 0xf9, 0xc6, 0x34, 0x74, 0xf3, 0xeb, 0x4d,
0x2e, 0x26, 0x2a, 0x85, 0x98, 0xd8, 0x85, 0x86, 0x69, 0x53, 0x5c, 0x74, 0x37, 0x70, 0x06, 0xcd,
0x10, 0x59, 0x7a, 0x54, 0xf3, 0x53, 0xce, 0x9f, 0xcc, 0xec, 0x61, 0x54, 0x53, 0xe3, 0x6e, 0x14,
0x92, 0x0f, 0xa1, 0xca, 0xf0, 0x84, 0x3a, 0xb6, 0x1f, 0xd9, 0xc5, 0x50, 0x28, 0x10, 0xef, 0xe9,
0x3f, 0xd4, 0x70, 0x90, 0xb7, 0x60, 0x33, 0x0a, 0x3c, 0x43, 0x32, 0x5e, 0x94, 0xf7, 0x22, 0x92,
0xbc, 0x87, 0x8f, 0x50, 0x90, 0xd9, 0x6a, 0x5e, 0x5f, 0x79, 0x05, 0x4d, 0xa9, 0x54, 0xbb, 0xab,
0x1a, 0xed, 0x6e, 0xc0, 0xe6, 0xc1, 0xf0, 0xab, 0x7e, 0x8f, 0x0e, 0x9c, 0xde, 0x60, 0x80, 0x99,
0x44, 0xa0, 0xdd, 0xeb, 0xf7, 0x8f, 0xc6, 0xa3, 0xd3, 0x13, 0x83, 0xb3, 0xc8, 0x4d, 0xd8, 0x4a,
0xc9, 0x06, 0xc3, 0xa7, 0x43, 0x5d, 0x5f, 0xb6, 0xa1, 0xb3, 0x20, 0xa4, 0xc3, 0xc3, 0xa3, 0x67,
0x58, 0x67, 0x00, 0xaa, 0x4f, 0x8f, 0xfa, 0x07, 0xaa, 0xca, 0xa8, 0xa4, 0x1c, 0x8f, 0x0c, 0xb4,
0x41, 0xb6, 0xa0, 0x39, 0xde, 0x1f, 0x38, 0xe3, 0xe3, 0x41, 0x4f, 0x09, 0xa8, 0x92, 0x0e, 0xb4,
0x46, 0xbd, 0xc3, 0xa1, 0xd3, 0x7f, 0xd2, 0x1b, 0x7d, 0x3e, 0x1c, 0x74, 0x6a, 0xf6, 0xd7, 0xba,
0xdb, 0xf5, 0x82, 0xc0, 0x28, 0x2d, 0xc8, 0xff, 0x43, 0xdd, 0xe8, 0x9d, 0xc6, 0xe1, 0x9a, 0xe7,
0x2d, 0xc8, 0x32, 0xf7, 0x94, 0x72, 0xee, 0x79, 0xbc, 0xf9, 0x75, 0x73, 0xef, 0xbd, 0x8f, 0x52,
0xd6, 0xb3, 0x2a, 0x9e, 0xde, 0xff, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd5, 0xde, 0xb0, 0x84,
0x97, 0x1c, 0x00, 0x00,
}

View File

@ -298,3 +298,34 @@ message SyncRawMessage {
bytes subAccountsJsonBytes = 2;
bytes settingsJsonBytes = 3;
}
message SyncKeycard {
string uid = 1;
string name = 2;
bool locked = 3;
string key_uid = 4;
repeated bytes addresses = 5;
uint64 clock = 6;
}
message SyncKeycardAction {
Action action = 1;
string oldKeycardUid = 2;
SyncKeycard keycard = 3;
enum Action {
KEYCARD_ADDED = 0;
ACCOUNTS_ADDED = 1;
KEYCARD_DELETED = 2;
ACCOUNTS_REMOVED = 3;
LOCKED = 4;
UNLOCKED = 5;
UID_UPDATED = 6;
NAME_CHANGED = 7;
}
}
message SyncAllKeycards {
repeated SyncKeycard keycards = 1;
uint64 clock = 2;
}

View File

@ -318,6 +318,10 @@ func (m *StatusMessage) HandleApplication() error {
return m.unmarshalProtobufData((new(protobuf.SyncContactRequestDecision)))
case protobuf.ApplicationMetadataMessage_SYNC_SAVED_ADDRESS:
return m.unmarshalProtobufData(new(protobuf.SyncSavedAddress))
case protobuf.ApplicationMetadataMessage_SYNC_ALL_KEYCARDS:
return m.unmarshalProtobufData(new(protobuf.SyncAllKeycards))
case protobuf.ApplicationMetadataMessage_SYNC_KEYCARD_ACTION:
return m.unmarshalProtobufData(new(protobuf.SyncKeycardAction))
}
return nil
}

View File

@ -454,7 +454,7 @@ func (api *API) AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(ctx context.Cont
kp.AccountsAddresses = append(kp.AccountsAddresses, types.Address(common.HexToAddress(addr)))
}
added, err := api.db.AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(kp)
added, err := (*api.messenger).AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(ctx, &kp)
if err != nil {
return err
}
@ -472,14 +472,8 @@ func (api *API) AddMigratedKeyPairOrAddAccountsIfKeyPairIsAdded(ctx context.Cont
}
func (api *API) RemoveMigratedAccountsForKeycard(ctx context.Context, kcUID string, accountAddresses []string) error {
var addresses []types.Address
for _, addr := range accountAddresses {
addresses = append(addresses, types.Address(common.HexToAddress(addr)))
}
clock := uint64(time.Now().Unix())
_, err := api.db.RemoveMigratedAccountsForKeycard(kcUID, addresses, clock)
return err
return (*api.messenger).RemoveMigratedAccountsForKeycard(ctx, kcUID, accountAddresses, clock)
}
func (api *API) GetAllKnownKeycards(ctx context.Context) ([]*keypairs.KeyPair, error) {
@ -496,26 +490,22 @@ func (api *API) GetMigratedKeyPairByKeyUID(ctx context.Context, keyUID string) (
func (api *API) SetKeycardName(ctx context.Context, kcUID string, kpName string) error {
clock := uint64(time.Now().Unix())
_, err := api.db.SetKeycardName(kcUID, kpName, clock)
return err
return (*api.messenger).SetKeycardName(ctx, kcUID, kpName, clock)
}
func (api *API) KeycardLocked(ctx context.Context, kcUID string) error {
clock := uint64(time.Now().Unix())
_, err := api.db.KeycardLocked(kcUID, clock)
return err
return (*api.messenger).KeycardLocked(ctx, kcUID, clock)
}
func (api *API) KeycardUnlocked(ctx context.Context, kcUID string) error {
clock := uint64(time.Now().Unix())
_, err := api.db.KeycardUnlocked(kcUID, clock)
return err
return (*api.messenger).KeycardUnlocked(ctx, kcUID, clock)
}
func (api *API) DeleteKeycard(ctx context.Context, kcUID string) error {
clock := uint64(time.Now().Unix())
_, err := api.db.DeleteKeycard(kcUID, clock)
return err
return (*api.messenger).DeleteKeycard(ctx, kcUID, clock)
}
func (api *API) DeleteKeypair(ctx context.Context, keyUID string) error {
@ -524,6 +514,5 @@ func (api *API) DeleteKeypair(ctx context.Context, keyUID string) error {
func (api *API) UpdateKeycardUID(ctx context.Context, oldKcUID string, newKcUID string) error {
clock := uint64(time.Now().Unix())
_, err := api.db.UpdateKeycardUID(oldKcUID, newKcUID, clock)
return err
return (*api.messenger).UpdateKeycardUID(ctx, oldKcUID, newKcUID, clock)
}