chore: synchronization improvements applied to keycards

This is the second step of improvements over keypairs/keycards/accounts.
- `SyncKeycardAction` protobuf removed
- `SyncKeypair` protobuf is used for syncing keycards state as well as for all
keycards related changes
- `last_update_clock` column removed from `keypairs` table cause as well as
for accounts, any keycard related change is actually a change made on a related
keypair, thus a keypair's clock keeps the clock of the last change
- `position` column added to `keypairs` table, needed to display keycards in
the same order accross devices
This commit is contained in:
Sale Djenic 2023-07-05 14:41:58 +02:00 committed by saledjenic
parent ca5075c149
commit 7063ad11aa
23 changed files with 1463 additions and 2256 deletions

View File

@ -1 +1 @@
0.161.4
0.161.5

View File

@ -999,7 +999,7 @@ func TestConvertAccount(t *testing.T) {
require.NoError(t, err)
// Check that there is no registered keycards
keycards, err := db.GetKeycardByKeyUID(genAccInfo.KeyUID)
keycards, err := db.GetKeycardsWithSameKeyUID(genAccInfo.KeyUID)
require.NoError(t, err)
require.Equal(t, 0, len(keycards))
@ -1026,7 +1026,7 @@ func TestConvertAccount(t *testing.T) {
require.NoError(t, err)
// Check that there is a registered keycard
keycards, err = db1.GetKeycardByKeyUID(genAccInfo.KeyUID)
keycards, err = db1.GetKeycardsWithSameKeyUID(genAccInfo.KeyUID)
require.NoError(t, err)
require.Equal(t, 1, len(keycards))
@ -1059,7 +1059,7 @@ func TestConvertAccount(t *testing.T) {
require.NoError(t, err)
// Check that there is no registered keycards
keycards, err = db2.GetKeycardByKeyUID(genAccInfo.KeyUID)
keycards, err = db2.GetKeycardsWithSameKeyUID(genAccInfo.KeyUID)
require.NoError(t, err)
require.Equal(t, 0, len(keycards))

View File

@ -923,24 +923,26 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun
return err
}
position, err := accountDB.GetPositionForNextNewKeycard()
if err != nil {
return err
}
kc := accounts.Keycard{
KeycardUID: keycardUID,
KeycardName: displayName,
KeycardLocked: false,
KeyUID: account.KeyUID,
LastUpdateClock: uint64(time.Now().Unix()),
Position: position,
}
for _, acc := range keypair.Accounts {
kc.AccountsAddresses = append(kc.AccountsAddresses, acc.Address)
}
addedKc, _, err := accountDB.AddKeycardOrAddAccountsIfKeycardIsAdded(kc)
err = accountDB.SaveOrUpdateKeycard(kc, uint64(time.Now().Unix()), true)
if err != nil {
return err
}
if !addedKc {
return errors.New("couldn't register a keycard to keycards table")
}
}
masterAddress, err := accountDB.GetMasterAddress()
@ -1191,7 +1193,7 @@ func (b *GethStatusBackend) ConvertToRegularAccount(mnemonic string, currPasswor
return err
}
err = db.DeleteAllKeycardsWithKeyUID(accountInfo.KeyUID)
err = db.DeleteAllKeycardsWithKeyUID(accountInfo.KeyUID, uint64(time.Now().Unix()))
if err != nil {
return err
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
ALTER TABLE keycards RENAME TO keycards_old;
ALTER TABLE keycards_accounts RENAME TO keycards_accounts_old;
CREATE TABLE IF NOT EXISTS keycards (
keycard_uid VARCHAR NOT NULL PRIMARY KEY,
keycard_name VARCHAR NOT NULL,
keycard_locked BOOLEAN DEFAULT FALSE,
key_uid VARCHAR NOT NULL,
position INT NOT NULL DEFAULT 0,
FOREIGN KEY(key_uid) REFERENCES keypairs(key_uid)
ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS keycards_accounts (
keycard_uid VARCHAR NOT NULL,
account_address VARCHAR NOT NULL,
PRIMARY KEY (keycard_uid, account_address),
FOREIGN KEY(keycard_uid) REFERENCES keycards(keycard_uid)
ON UPDATE CASCADE
ON DELETE CASCADE
);
INSERT INTO keycards
SELECT keycard_uid, keycard_name, keycard_locked, key_uid, last_update_clock
FROM keycards_old
ORDER BY last_update_clock;
INSERT INTO keycards_accounts
SELECT keycard_uid, account_address
FROM keycards_accounts_old;
UPDATE keycards SET position = rowid - 1;
DROP TABLE keycards_accounts_old;
DROP TABLE keycards_old;

View File

@ -220,7 +220,6 @@ func (a *Keypair) CopyKeypair() *Keypair {
KeycardLocked: kc.KeycardLocked,
AccountsAddresses: kc.AccountsAddresses,
KeyUID: kc.KeyUID,
LastUpdateClock: kc.LastUpdateClock,
}
}
@ -242,7 +241,6 @@ type Database struct {
*settings.Database
*notificationssettings.NotificationsSettings
*sociallinkssettings.SocialLinksSettings
*Keycards
db *sql.DB
}
@ -254,9 +252,8 @@ func NewDB(db *sql.DB) (*Database, error) {
}
sn := notificationssettings.NewNotificationsSettings(db)
ssl := sociallinkssettings.NewSocialLinksSettings(db)
kc := NewKeycards(db)
return &Database{sDB, sn, ssl, kc, db}, nil
return &Database{sDB, sn, ssl, db}, nil
}
// DB Gets db sql.DB
@ -486,7 +483,7 @@ func (db *Database) getKeypairs(tx *sql.Tx, keyUID string) ([]*Keypair, error) {
}
for _, kp := range keypairs {
keycards, err := db.getAllRows(tx, true)
keycards, err := db.getKeycards(tx, kp.KeyUID, "")
if err != nil {
return nil, err
}
@ -803,11 +800,6 @@ func (db *Database) saveOrUpdateAccounts(tx *sql.Tx, accounts []*Account, update
}
keyUID = &acc.KeyUID
}
var exists bool
err = tx.QueryRow("SELECT EXISTS (SELECT 1 FROM keypairs_accounts WHERE address = ?)", acc.Address).Scan(&exists)
if err != nil {
return err
}
_, err = tx.Exec(`
INSERT OR IGNORE INTO
@ -882,6 +874,7 @@ func (db *Database) saveOrUpdateAccounts(tx *sql.Tx, accounts []*Account, update
return nil
}
// Saves accounts, if an account already exists, it will be updated.
func (db *Database) SaveOrUpdateAccounts(accounts []*Account, updateKeypairClock bool) error {
if len(accounts) == 0 {
return errors.New("no provided accounts to save/update")
@ -902,6 +895,10 @@ func (db *Database) SaveOrUpdateAccounts(accounts []*Account, updateKeypairClock
return err
}
// Saves a keypair and its accounts, if a keypair with `key_uid` already exists, it will be updated,
// if any of its accounts exists it will be updated as well, otherwise it will be added.
// Since keypair type contains `Keycards` as well, they are excluded from the saving/updating this way regardless they
// are set or not.
func (db *Database) SaveOrUpdateKeypair(keypair *Keypair) error {
if keypair == nil {
return errDbPassedParameterIsNil
@ -1063,6 +1060,23 @@ func (db *Database) GetAddresses() (rst []types.Address, err error) {
return rst, nil
}
func (db *Database) keypairExists(tx *sql.Tx, keyUID string) (exists bool, err error) {
query := `SELECT EXISTS (SELECT 1 FROM keypairs WHERE key_uid = ?)`
if tx == nil {
err = db.db.QueryRow(query, keyUID).Scan(&exists)
} else {
err = tx.QueryRow(query, keyUID).Scan(&exists)
}
return exists, err
}
// KeypairExists returns true if given address is stored in database.
func (db *Database) KeypairExists(keyUID string) (exists bool, err error) {
return db.keypairExists(nil, keyUID)
}
// AddressExists returns true if given address is stored in database.
func (db *Database) AddressExists(address types.Address) (exists bool, err error) {
err = db.db.QueryRow("SELECT EXISTS (SELECT 1 FROM keypairs_accounts WHERE address = ?)", address).Scan(&exists)

View File

@ -10,7 +10,11 @@ import (
"github.com/status-im/status-go/protocol/protobuf"
)
var errKeycardDbTransactionIsNil = errors.New("keycard: database transaction is nil")
var (
errKeycardDbTransactionIsNil = errors.New("keycard: database transaction is nil")
errCannotAddKeycardForUnknownKeypair = errors.New("keycard: cannot add keycard for an unknown keyapir")
ErrNoKeycardForPassedKeycardUID = errors.New("keycard: no keycard for the passed keycard uid")
)
type Keycard struct {
KeycardUID string `json:"keycard-uid"`
@ -18,13 +22,7 @@ type Keycard struct {
KeycardLocked bool `json:"keycard-locked"`
AccountsAddresses []types.Address `json:"accounts-addresses"`
KeyUID string `json:"key-uid"`
LastUpdateClock uint64
}
type KeycardAction struct {
Action string `json:"action"`
OldKeycardUID string `json:"old-keycard-uid,omitempty"`
Keycard *Keycard `json:"keycard"`
Position uint64
}
func (kp *Keycard) ToSyncKeycard() *protobuf.SyncKeycard {
@ -33,7 +31,7 @@ func (kp *Keycard) ToSyncKeycard() *protobuf.SyncKeycard {
Name: kp.KeycardName,
Locked: kp.KeycardLocked,
KeyUid: kp.KeyUID,
Clock: kp.LastUpdateClock,
Position: kp.Position,
}
for _, addr := range kp.AccountsAddresses {
@ -48,30 +46,13 @@ func (kp *Keycard) FromSyncKeycard(kc *protobuf.SyncKeycard) {
kp.KeycardName = kc.Name
kp.KeycardLocked = kc.Locked
kp.KeyUID = kc.KeyUid
kp.LastUpdateClock = kc.Clock
kp.Position = kc.Position
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 Keycards struct {
db *sql.DB
}
func NewKeycards(db *sql.DB) *Keycards {
return &Keycards{
db: db,
}
}
func containsAddress(addresses []types.Address, address types.Address) bool {
for _, addr := range addresses {
if addr == address {
@ -81,30 +62,28 @@ func containsAddress(addresses []types.Address, address types.Address) bool {
return false
}
func (kp *Keycards) processResult(rows *sql.Rows, groupByKeycard bool) ([]*Keycard, error) {
func (db *Database) processResult(rows *sql.Rows) ([]*Keycard, error) {
keycards := []*Keycard{}
for rows.Next() {
keycard := &Keycard{}
addr := types.Address{}
err := rows.Scan(&keycard.KeycardUID, &keycard.KeycardName, &keycard.KeycardLocked, &addr, &keycard.KeyUID,
&keycard.LastUpdateClock)
var accAddress sql.NullString
err := rows.Scan(&keycard.KeycardUID, &keycard.KeycardName, &keycard.KeycardLocked, &accAddress, &keycard.KeyUID,
&keycard.Position)
if err != nil {
return nil, err
}
addr := types.Address{}
if accAddress.Valid {
addr = types.BytesToAddress([]byte(accAddress.String))
}
foundAtIndex := -1
for i := range keycards {
if groupByKeycard {
if keycards[i].KeycardUID == keycard.KeycardUID {
foundAtIndex = i
break
}
} else {
if keycards[i].KeyUID == keycard.KeyUID {
foundAtIndex = i
break
}
}
}
if foundAtIndex == -1 {
keycard.AccountsAddresses = append(keycard.AccountsAddresses, addr)
@ -120,152 +99,104 @@ func (kp *Keycards) processResult(rows *sql.Rows, groupByKeycard bool) ([]*Keyca
return keycards, nil
}
func (kp *Keycards) getAllRows(tx *sql.Tx, groupByKeycard bool) ([]*Keycard, error) {
var (
rows *sql.Rows
err error
)
query := // nolint: gosec
`
func (db *Database) getKeycards(tx *sql.Tx, keyUID string, keycardUID string) ([]*Keycard, error) {
query := `
SELECT
k.keycard_uid,
k.keycard_name,
k.keycard_locked,
kc.keycard_uid,
kc.keycard_name,
kc.keycard_locked,
ka.account_address,
k.key_uid,
k.last_update_clock
kc.key_uid,
kc.position
FROM
keycards AS k
keycards AS kc
LEFT JOIN
keycards_accounts AS ka
ON
k.keycard_uid = ka.keycard_uid
kc.keycard_uid = ka.keycard_uid
LEFT JOIN
keypairs_accounts AS kpa
ON
ka.account_address = kpa.address
%s
ORDER BY
key_uid`
kc.position, kpa.position`
if tx == nil {
rows, err = kp.db.Query(query)
if err != nil {
return nil, err
var where string
var args []interface{}
if keyUID != "" {
where = "WHERE kc.key_uid = ?"
args = append(args, keyUID)
if keycardUID != "" {
where += " AND kc.keycard_uid = ?"
args = append(args, keycardUID)
}
} else if keycardUID != "" {
where = "WHERE kc.keycard_uid = ?"
args = append(args, keycardUID)
}
query = fmt.Sprintf(query, where)
var (
stmt *sql.Stmt
err error
)
if tx == nil {
stmt, err = db.db.Prepare(query)
} else {
stmt, err := tx.Prepare(query)
stmt, err = tx.Prepare(query)
}
if err != nil {
return nil, err
}
defer stmt.Close()
rows, err = stmt.Query()
rows, err := stmt.Query(args...)
if err != nil {
return nil, err
}
}
defer rows.Close()
return kp.processResult(rows, groupByKeycard)
return db.processResult(rows)
}
func (kp *Keycards) GetAllKnownKeycards() ([]*Keycard, error) {
return kp.getAllRows(nil, true)
}
func (kp *Keycards) GetAllKnownKeycardsGroupedByKeyUID() ([]*Keycard, error) {
return kp.getAllRows(nil, false)
}
func (kp *Keycards) GetKeycardByKeyUID(keyUID string) ([]*Keycard, error) {
rows, err := kp.db.Query(`
SELECT
k.keycard_uid,
k.keycard_name,
k.keycard_locked,
ka.account_address,
k.key_uid,
k.last_update_clock
FROM
keycards AS k
LEFT JOIN
keycards_accounts AS ka
ON
k.keycard_uid = ka.keycard_uid
WHERE
k.key_uid = ?
ORDER BY
k.keycard_uid
`, keyUID)
func (db *Database) getKeycardByKeycardUID(tx *sql.Tx, keycardUID string) (*Keycard, error) {
keycards, err := db.getKeycards(tx, "", keycardUID)
if err != nil {
if err == sql.ErrNoRows {
return []*Keycard{}, nil
}
return nil, err
}
defer rows.Close()
return kp.processResult(rows, false)
if len(keycards) == 0 {
return nil, ErrNoKeycardForPassedKeycardUID
}
func (kp *Keycards) startTransactionAndCheckIfNeedToProceed(kcUID string, clock uint64) (tx *sql.Tx, proceed bool, err error) {
tx, err = kp.db.Begin()
if err != nil {
return nil, false, err
}
var dbLastUpdateClock uint64
err = tx.QueryRow(`SELECT last_update_clock FROM keycards WHERE keycard_uid = ?`, kcUID).Scan(&dbLastUpdateClock)
if err != nil {
return tx, err == sql.ErrNoRows, err
return keycards[0], nil
}
return tx, dbLastUpdateClock <= clock, nil
func (db *Database) GetAllKnownKeycards() ([]*Keycard, error) {
return db.getKeycards(nil, "", "")
}
func (kp *Keycards) setLastUpdateClock(tx *sql.Tx, kcUID string, clock uint64) (err error) {
func (db *Database) GetKeycardsWithSameKeyUID(keyUID string) ([]*Keycard, error) {
return db.getKeycards(nil, keyUID, "")
}
func (db *Database) GetKeycardByKeycardUID(keycardUID string) (*Keycard, error) {
return db.getKeycardByKeycardUID(nil, keycardUID)
}
func (db *Database) saveOrUpdateKeycardAccounts(tx *sql.Tx, kcUID string, accountsAddresses []types.Address) (err error) {
if tx == nil {
return errKeycardDbTransactionIsNil
}
for i := range accountsAddresses {
addr := accountsAddresses[i]
_, err = tx.Exec(`
UPDATE
keycards
SET
last_update_clock = ?
WHERE
keycard_uid = ?`,
clock, kcUID)
return err
}
func (kp *Keycards) getAccountsForKeycard(tx *sql.Tx, kcUID string) ([]types.Address, error) {
var accountAddresses []types.Address
if tx == nil {
return accountAddresses, errKeycardDbTransactionIsNil
}
rows, err := tx.Query(`SELECT account_address FROM keycards_accounts WHERE keycard_uid = ?`, kcUID)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var accAddress types.Address
err = rows.Scan(&accAddress)
if err != nil {
return nil, err
}
accountAddresses = append(accountAddresses, accAddress)
}
return accountAddresses, nil
}
func (kp *Keycards) addAccounts(tx *sql.Tx, kcUID string, accountsAddresses []types.Address) (err error) {
if tx == nil {
return errKeycardDbTransactionIsNil
}
insertKcAcc, err := tx.Prepare(`
INSERT INTO
INSERT OR IGNORE INTO
keycards_accounts
(
keycard_uid,
@ -273,26 +204,17 @@ func (kp *Keycards) addAccounts(tx *sql.Tx, kcUID string, accountsAddresses []ty
)
VALUES
(?, ?);
`)
`, kcUID, addr)
if err != nil {
return err
}
defer insertKcAcc.Close()
for i := range accountsAddresses {
addr := accountsAddresses[i]
_, err = insertKcAcc.Exec(kcUID, addr)
if err != nil {
return err
}
}
return nil
}
func (kp *Keycards) deleteKeycard(tx *sql.Tx, kcUID string) (err error) {
func (db *Database) deleteKeycard(tx *sql.Tx, kcUID string) (err error) {
if tx == nil {
return errKeycardDbTransactionIsNil
}
@ -314,182 +236,9 @@ func (kp *Keycards) deleteKeycard(tx *sql.Tx, kcUID string) (err error) {
return err
}
func (kp *Keycards) AddKeycardOrAddAccountsIfKeycardIsAdded(keycard Keycard) (addedKc bool, addedAccs bool, err error) {
tx, proceed, err := kp.startTransactionAndCheckIfNeedToProceed(keycard.KeycardUID, keycard.LastUpdateClock)
defer func() {
if err == nil {
err = tx.Commit()
return
}
_ = tx.Rollback()
}()
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
(
keycard_uid,
keycard_name,
keycard_locked,
key_uid,
last_update_clock
)
VALUES
(?, ?, ?, ?, ?);`,
keycard.KeycardUID, keycard.KeycardName, keycard.KeycardLocked, keycard.KeyUID, keycard.LastUpdateClock)
if err != nil {
return false, false, err
}
err = kp.addAccounts(tx, keycard.KeycardUID, keycard.AccountsAddresses)
return err == nil, false, err
}
err = kp.setLastUpdateClock(tx, keycard.KeycardUID, keycard.LastUpdateClock)
if err != nil {
return false, false, err
}
err = kp.addAccounts(tx, keycard.KeycardUID, keycard.AccountsAddresses)
return false, err == nil, err
}
return false, false, err
}
func (kp *Keycards) ApplyKeycardsForKeypairWithKeyUID(keyUID string, keycardsToSync []*Keycard) (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 WHERE key_uid = ?`, keyUID)
if err != nil && err != sql.ErrNoRows {
return err
}
defer rows.Close()
var dbKeycards []*Keycard
for rows.Next() {
keycard := &Keycard{}
err := rows.Scan(&keycard.KeycardUID, &keycard.KeycardName, &keycard.KeycardLocked, &keycard.KeyUID,
&keycard.LastUpdateClock)
if err != nil {
return err
}
dbKeycards = append(dbKeycards, keycard)
}
// apply those from `keycardsToSync` which are newer
for _, syncKc := range keycardsToSync {
foundAtIndex := -1
for i := range dbKeycards {
if dbKeycards[i].KeycardUID == syncKc.KeycardUID {
foundAtIndex = i
break
}
}
if foundAtIndex > -1 {
dbClock := dbKeycards[foundAtIndex].LastUpdateClock
dbKeycards = removeElementAtIndex(dbKeycards, foundAtIndex)
if dbClock > syncKc.LastUpdateClock {
continue
}
err = kp.deleteKeycard(tx, syncKc.KeycardUID)
if err != nil {
return err
}
}
_, err = tx.Exec(`
INSERT OR REPLACE INTO
keycards
(
keycard_uid,
keycard_name,
keycard_locked,
key_uid,
last_update_clock
)
VALUES
(?, ?, ?, ?, ?);`,
syncKc.KeycardUID, syncKc.KeycardName, syncKc.KeycardLocked, syncKc.KeyUID, syncKc.LastUpdateClock)
if err != nil {
return err
}
err = kp.addAccounts(tx, syncKc.KeycardUID, syncKc.AccountsAddresses)
if err != nil {
return err
}
}
// remove those from the db if they are not in `keycardsToSync`
for _, dbKp := range dbKeycards {
err = kp.deleteKeycard(tx, dbKp.KeycardUID)
if err != nil {
return err
}
}
return nil
}
func (kp *Keycards) RemoveMigratedAccountsForKeycard(kcUID string, accountAddresses []types.Address,
clock uint64) (err error) {
tx, proceed, err := kp.startTransactionAndCheckIfNeedToProceed(kcUID, clock)
defer func() {
if err == nil {
err = tx.Commit()
return
}
_ = tx.Rollback()
}()
if err != nil {
return err
}
if proceed {
err = kp.setLastUpdateClock(tx, kcUID, clock)
if err != nil {
return err
}
dbAccountAddresses, err := kp.getAccountsForKeycard(tx, kcUID)
if err != nil {
return err
}
deleteKeycard := true
for _, dbAddr := range dbAccountAddresses {
found := false
for _, addr := range accountAddresses {
if dbAddr == addr {
found = true
}
}
if !found {
deleteKeycard = false
}
}
if deleteKeycard {
return kp.deleteKeycard(tx, kcUID)
func (db *Database) deleteKeycardAccounts(tx *sql.Tx, kcUID string, accountAddresses []types.Address) (err error) {
if tx == nil {
return errKeycardDbTransactionIsNil
}
inVector := strings.Repeat(",?", len(accountAddresses)-1)
@ -500,12 +249,13 @@ func (kp *Keycards) RemoveMigratedAccountsForKeycard(kcUID string, accountAddres
WHERE
keycard_uid = ?
AND
account_address IN (?` + inVector + `)
`
account_address IN (?` + inVector + `)`
delete, err := tx.Prepare(query)
if err != nil {
return err
}
defer delete.Close()
args := make([]interface{}, len(accountAddresses)+1)
args[0] = kcUID
@ -513,18 +263,16 @@ func (kp *Keycards) RemoveMigratedAccountsForKeycard(kcUID string, accountAddres
args[i+1] = addr
}
defer delete.Close()
_, err = delete.Exec(args...)
return err
}
func (db *Database) SaveOrUpdateKeycard(keycard Keycard, clock uint64, updateKeypairClock bool) error {
tx, err := db.db.Begin()
if err != nil {
return err
}
func (kp *Keycards) execUpdateQuery(kcUID string, clock uint64, field string, value interface{}) (err error) {
tx, proceed, err := kp.startTransactionAndCheckIfNeedToProceed(kcUID, clock)
defer func() {
if err == nil {
err = tx.Commit()
@ -533,37 +281,57 @@ func (kp *Keycards) execUpdateQuery(kcUID string, clock uint64, field string, va
_ = tx.Rollback()
}()
relatedKeypairExists, err := db.keypairExists(tx, keycard.KeyUID)
if err != nil {
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)
if !relatedKeypairExists {
return errCannotAddKeycardForUnknownKeypair
}
_, err = tx.Exec(`
INSERT OR IGNORE INTO
keycards
(
keycard_uid,
keycard_name,
key_uid
)
VALUES
(?, ?, ?);
UPDATE
keycards
SET
keycard_name = ?,
keycard_locked = ?,
position = ?
WHERE
keycard_uid = ?;
`, keycard.KeycardUID, keycard.KeycardName, keycard.KeyUID,
keycard.KeycardName, keycard.KeycardLocked, keycard.Position, keycard.KeycardUID)
if err != nil {
return err
}
err = db.saveOrUpdateKeycardAccounts(tx, keycard.KeycardUID, keycard.AccountsAddresses)
if err != nil {
return err
}
if updateKeypairClock {
return db.updateKeypairClock(tx, keycard.KeyUID, clock)
}
return nil
}
func (kp *Keycards) KeycardLocked(kcUID string, clock uint64) (err error) {
return kp.execUpdateQuery(kcUID, clock, "keycard_locked", true)
func (db *Database) execKeycardUpdateQuery(kcUID string, clock uint64, field string, value interface{}) (err error) {
tx, err := db.db.Begin()
if err != nil {
return err
}
func (kp *Keycards) KeycardUnlocked(kcUID string, clock uint64) (err error) {
return kp.execUpdateQuery(kcUID, clock, "keycard_locked", false)
}
func (kp *Keycards) UpdateKeycardUID(oldKcUID string, newKcUID string, clock uint64) (err error) {
return kp.execUpdateQuery(oldKcUID, clock, "keycard_uid", newKcUID)
}
func (kp *Keycards) SetKeycardName(kcUID string, kpName string, clock uint64) (err error) {
return kp.execUpdateQuery(kcUID, clock, "keycard_name", kpName)
}
func (kp *Keycards) DeleteKeycard(kcUID string, clock uint64) (err error) {
tx, proceed, err := kp.startTransactionAndCheckIfNeedToProceed(kcUID, clock)
defer func() {
if err == nil {
err = tx.Commit()
@ -572,19 +340,102 @@ func (kp *Keycards) DeleteKeycard(kcUID string, clock uint64) (err error) {
_ = tx.Rollback()
}()
keycard, err := db.getKeycardByKeycardUID(tx, kcUID)
if err != nil {
return err
}
if proceed {
return kp.deleteKeycard(tx, kcUID)
}
sql := fmt.Sprintf(`UPDATE keycards SET %s = ? WHERE keycard_uid = ?`, field) // nolint: gosec
_, err = tx.Exec(sql, value, kcUID)
if err != nil {
return err
}
func (kp *Keycards) DeleteAllKeycardsWithKeyUID(keyUID string) (err error) {
delete, err := kp.db.Prepare(`
return db.updateKeypairClock(tx, keycard.KeyUID, clock)
}
func (db *Database) KeycardLocked(kcUID string, clock uint64) (err error) {
return db.execKeycardUpdateQuery(kcUID, clock, "keycard_locked", true)
}
func (db *Database) KeycardUnlocked(kcUID string, clock uint64) (err error) {
return db.execKeycardUpdateQuery(kcUID, clock, "keycard_locked", false)
}
func (db *Database) UpdateKeycardUID(oldKcUID string, newKcUID string, clock uint64) (err error) {
return db.execKeycardUpdateQuery(oldKcUID, clock, "keycard_uid", newKcUID)
}
func (db *Database) SetKeycardName(kcUID string, kpName string, clock uint64) (err error) {
return db.execKeycardUpdateQuery(kcUID, clock, "keycard_name", kpName)
}
func (db *Database) DeleteKeycardAccounts(kcUID string, accountAddresses []types.Address, clock uint64) (err error) {
tx, err := db.db.Begin()
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
_ = tx.Rollback()
}()
keycard, err := db.getKeycardByKeycardUID(tx, kcUID)
if err != nil {
return err
}
err = db.deleteKeycardAccounts(tx, kcUID, accountAddresses)
if err != nil {
return err
}
return db.updateKeypairClock(tx, keycard.KeyUID, clock)
}
func (db *Database) DeleteKeycard(kcUID string, clock uint64) (err error) {
tx, err := db.db.Begin()
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
_ = tx.Rollback()
}()
keycard, err := db.getKeycardByKeycardUID(tx, kcUID)
if err != nil {
return err
}
err = db.deleteKeycard(tx, kcUID)
if err != nil {
return err
}
return db.updateKeypairClock(tx, keycard.KeyUID, clock)
}
func (db *Database) DeleteAllKeycardsWithKeyUID(keyUID string, clock uint64) (err error) {
tx, err := db.db.Begin()
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
_ = tx.Rollback()
}()
delete, err := tx.Prepare(`
DELETE
FROM
keycards
@ -595,6 +446,23 @@ func (kp *Keycards) DeleteAllKeycardsWithKeyUID(keyUID string) (err error) {
return err
}
defer delete.Close()
_, err = delete.Exec(keyUID)
if err != nil {
return err
}
return db.updateKeypairClock(tx, keyUID, clock)
}
func (db *Database) GetPositionForNextNewKeycard() (uint64, error) {
var pos sql.NullInt64
err := db.db.QueryRow("SELECT MAX(position) FROM keycards").Scan(&pos)
if err != nil {
return 0, err
}
if pos.Valid {
return uint64(pos.Int64) + 1, nil
}
return 0, nil
}

View File

@ -12,8 +12,6 @@ func TestKeycards(t *testing.T) {
db, stop := setupTestDB(t)
defer stop()
keycardUID := "00000000000000000000000000000000"
kp1 := GetProfileKeypairForTest(true, true, true)
keycard1 := GetProfileKeycardForTest()
@ -23,266 +21,151 @@ func TestKeycards(t *testing.T) {
keycard2Copy := GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1
kp3 := GetSeedImportedKeypair2ForTest()
keycard3 := GetKeycardForSeedImportedKeypair2ForTest()
keycard2Copy.Position = keycard2Copy.Position + 1
// Pre-condition
err := db.SaveOrUpdateKeypair(kp1)
require.NoError(t, err)
err = db.SaveOrUpdateKeypair(kp2)
require.NoError(t, err)
err = db.SaveOrUpdateKeypair(kp3)
require.NoError(t, err)
dbKeypairs, err := db.GetKeypairs()
require.NoError(t, err)
require.Equal(t, 3, len(dbKeypairs))
require.Equal(t, 2, len(dbKeypairs))
// Test adding key pairs
addedKc, addedAccs, err := db.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
// Test adding/reading keycards
err = db.SaveOrUpdateKeycard(*keycard1, 0, false)
require.NoError(t, err)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2)
dbKeycard1, err := db.GetKeycardByKeycardUID(keycard1.KeycardUID)
require.NoError(t, err)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy)
require.NoError(t, err)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
// this should be added
addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(Keycard{
KeycardUID: keycard2Copy.KeycardUID,
AccountsAddresses: []types.Address{{0x03}},
LastUpdateClock: keycard2Copy.LastUpdateClock + 1,
})
require.NoError(t, err)
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
addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(Keycard{
KeycardUID: keycard2Copy.KeycardUID,
AccountsAddresses: []types.Address{{0x04}},
LastUpdateClock: keycard2Copy.LastUpdateClock,
})
require.NoError(t, err)
require.Equal(t, false, addedKc)
require.Equal(t, false, addedAccs)
addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3)
require.NoError(t, err)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
require.True(t, SameKeycards(keycard1, dbKeycard1))
// Test reading migrated key pairs
rows, err := db.GetAllKnownKeycardsGroupedByKeyUID()
err = db.SaveOrUpdateKeycard(*keycard2, 0, false)
require.NoError(t, err)
require.Equal(t, 3, len(rows))
for _, kp := range rows {
if kp.KeyUID == keycard1.KeyUID {
require.Equal(t, keycard1.KeycardUID, kp.KeycardUID)
require.Equal(t, keycard1.KeycardName, kp.KeycardName)
require.Equal(t, keycard1.KeycardLocked, kp.KeycardLocked)
require.Equal(t, len(keycard1.AccountsAddresses), len(kp.AccountsAddresses))
} else if kp.KeyUID == keycard2.KeyUID { // keycard 2 and 3, cause 3 is a copy of 2
require.Equal(t, keycard2.KeycardUID, kp.KeycardUID)
require.Equal(t, keycard2.KeycardName, kp.KeycardName)
require.Equal(t, keycard2.KeycardLocked, kp.KeycardLocked)
require.Equal(t, len(keycard2.AccountsAddresses)+1, len(kp.AccountsAddresses)) // Add 1, cause one account is additionally added for the same keycard.
} else {
require.Equal(t, keycard3.KeycardUID, kp.KeycardUID)
require.Equal(t, keycard3.KeycardName, kp.KeycardName)
require.Equal(t, keycard3.KeycardLocked, kp.KeycardLocked)
require.Equal(t, len(keycard3.AccountsAddresses), len(kp.AccountsAddresses))
}
}
dbKeycard2, err := db.GetKeycardByKeycardUID(keycard2.KeycardUID)
require.NoError(t, err)
require.True(t, SameKeycards(keycard2, dbKeycard2))
rows, err = db.GetKeycardByKeyUID(keycard1.KeyUID)
err = db.SaveOrUpdateKeycard(*keycard2Copy, 0, false)
require.NoError(t, err)
require.Equal(t, 1, len(rows))
require.Equal(t, keycard1.KeyUID, rows[0].KeyUID)
require.Equal(t, keycard1.KeycardUID, rows[0].KeycardUID)
require.Equal(t, keycard1.KeycardName, rows[0].KeycardName)
require.Equal(t, keycard1.KeycardLocked, rows[0].KeycardLocked)
require.Equal(t, len(keycard1.AccountsAddresses), len(rows[0].AccountsAddresses))
require.Equal(t, keycard1.LastUpdateClock, rows[0].LastUpdateClock)
dbKeycard2Copy, err := db.GetKeycardByKeycardUID(keycard2Copy.KeycardUID)
require.NoError(t, err)
require.True(t, SameKeycards(keycard2Copy, dbKeycard2Copy))
rows, err = db.GetAllKnownKeycards()
dbKeycards, err := db.GetKeycardsWithSameKeyUID(keycard2.KeyUID)
require.NoError(t, err)
require.Equal(t, 4, len(rows))
for _, kp := range rows {
if kp.KeycardUID == keycard1.KeycardUID {
require.Equal(t, keycard1.KeycardUID, kp.KeycardUID)
require.Equal(t, keycard1.KeycardName, kp.KeycardName)
require.Equal(t, keycard1.KeycardLocked, kp.KeycardLocked)
require.Equal(t, len(keycard1.AccountsAddresses), len(kp.AccountsAddresses))
require.Equal(t, keycard1.LastUpdateClock, kp.LastUpdateClock)
} else if kp.KeycardUID == keycard2.KeycardUID {
require.Equal(t, keycard2.KeycardUID, kp.KeycardUID)
require.Equal(t, keycard2.KeycardName, kp.KeycardName)
require.Equal(t, keycard2.KeycardLocked, kp.KeycardLocked)
require.Equal(t, len(keycard2.AccountsAddresses), len(kp.AccountsAddresses))
require.Equal(t, keycard2.LastUpdateClock, kp.LastUpdateClock)
} else if kp.KeycardUID == keycard2Copy.KeycardUID {
require.Equal(t, keycard2Copy.KeycardUID, kp.KeycardUID)
require.Equal(t, keycard2Copy.KeycardName, kp.KeycardName)
require.Equal(t, keycard2Copy.KeycardLocked, kp.KeycardLocked)
require.Equal(t, len(keycard2Copy.AccountsAddresses)+1, len(kp.AccountsAddresses)) // Add 1, cause one account is additionally added.
require.Equal(t, keycard2Copy.LastUpdateClock+1, kp.LastUpdateClock)
} else {
require.Equal(t, keycard3.KeycardUID, kp.KeycardUID)
require.Equal(t, keycard3.KeycardName, kp.KeycardName)
require.Equal(t, keycard3.KeycardLocked, kp.KeycardLocked)
require.Equal(t, len(keycard3.AccountsAddresses), len(kp.AccountsAddresses))
require.Equal(t, keycard3.LastUpdateClock, kp.LastUpdateClock)
}
}
require.Equal(t, 2, len(dbKeycards))
require.True(t, Contains(dbKeycards, keycard2, SameKeycards))
require.True(t, Contains(dbKeycards, keycard2Copy, SameKeycards))
dbKeycards, err = db.GetAllKnownKeycards()
require.NoError(t, err)
require.Equal(t, 3, len(dbKeycards))
require.True(t, Contains(dbKeycards, keycard1, SameKeycards))
require.True(t, Contains(dbKeycards, keycard2, SameKeycards))
require.True(t, Contains(dbKeycards, keycard2Copy, SameKeycards))
nextPosition, err := db.GetPositionForNextNewKeycard()
require.NoError(t, err)
require.Equal(t, uint64(len(dbKeycards)), nextPosition)
// test adding additional accounts to keycard
keycard1.AccountsAddresses = append(keycard1.AccountsAddresses, types.Address{0x05}, types.Address{0x06})
err = db.SaveOrUpdateKeycard(*keycard1, 0, false)
require.NoError(t, err)
dbKeycard1, err = db.GetKeycardByKeycardUID(keycard1.KeycardUID)
require.NoError(t, err)
require.Equal(t, len(keycard1.AccountsAddresses), len(dbKeycard1.AccountsAddresses))
require.True(t, SameKeycards(keycard1, dbKeycard1))
// Test seting a new keycard name
err = db.SetKeycardName(keycard1.KeycardUID, "Card101", 1000)
keycard1.KeycardName = "Card101"
err = db.SetKeycardName(keycard1.KeycardUID, keycard1.KeycardName, 1000)
require.NoError(t, err)
rows, err = db.GetAllKnownKeycardsGroupedByKeyUID()
dbKeycard1, err = db.GetKeycardByKeycardUID(keycard1.KeycardUID)
require.NoError(t, err)
newKeycardName := ""
for _, kp := range rows {
if kp.KeyUID == keycard1.KeyUID {
newKeycardName = kp.KeycardName
}
}
require.Equal(t, "Card101", newKeycardName)
// Test seting a new keycard name with an old clock value
err = db.SetKeycardName(keycard1.KeycardUID, "Card102", 999) // clock is less than the last one
require.NoError(t, err)
rows, err = db.GetAllKnownKeycardsGroupedByKeyUID()
require.NoError(t, err)
newKeycardName = ""
for _, kp := range rows {
if kp.KeyUID == keycard1.KeyUID {
newKeycardName = kp.KeycardName
}
}
require.Equal(t, "Card101", newKeycardName)
require.True(t, SameKeycards(keycard1, dbKeycard1))
// Test locking a keycard
keycard1.KeycardLocked = true
err = db.KeycardLocked(keycard1.KeycardUID, 1001)
require.NoError(t, err)
rows, err = db.GetAllKnownKeycardsGroupedByKeyUID()
dbKeycard1, err = db.GetKeycardByKeycardUID(keycard1.KeycardUID)
require.NoError(t, err)
locked := false
for _, kp := range rows {
if kp.KeyUID == keycard1.KeyUID {
locked = kp.KeycardLocked
}
}
require.Equal(t, true, locked)
require.True(t, SameKeycards(keycard1, dbKeycard1))
// Test unlocking a keycard
keycard1.KeycardLocked = false
err = db.KeycardUnlocked(keycard1.KeycardUID, 1002)
require.NoError(t, err)
dbKeycard1, err = db.GetKeycardByKeycardUID(keycard1.KeycardUID)
require.NoError(t, err)
require.True(t, SameKeycards(keycard1, dbKeycard1))
// Test update keycard uid
oldKeycardUID := keycard1.KeycardUID
keycard1.KeycardUID = "00000000000000000000000000000000"
err = db.UpdateKeycardUID(oldKeycardUID, keycard1.KeycardUID, 1003)
require.NoError(t, err)
dbKeycard1, err = db.GetKeycardByKeycardUID(keycard1.KeycardUID)
require.NoError(t, err)
require.True(t, SameKeycards(keycard1, dbKeycard1))
// Test detleting accounts (addresses) for a certain keycard
const numOfAccountsToRemove = 2
require.Greater(t, len(keycard1.AccountsAddresses), numOfAccountsToRemove)
accountsToRemove := keycard1.AccountsAddresses[:numOfAccountsToRemove]
err = db.RemoveMigratedAccountsForKeycard(keycard1.KeycardUID, accountsToRemove, 1002)
keycard1.AccountsAddresses = keycard1.AccountsAddresses[numOfAccountsToRemove:]
err = db.DeleteKeycardAccounts(keycard1.KeycardUID, accountsToRemove, 1004)
require.NoError(t, err)
rows, err = db.GetKeycardByKeyUID(keycard1.KeyUID)
dbKeycard1, err = db.GetKeycardByKeycardUID(keycard1.KeycardUID)
require.NoError(t, err)
require.Equal(t, 1, len(rows))
require.Equal(t, len(keycard1.AccountsAddresses)-numOfAccountsToRemove, len(rows[0].AccountsAddresses))
// Test deleting accounts one by one, with the last deleted account keycard should be delete as well
for i, addr := range keycard3.AccountsAddresses {
err = db.RemoveMigratedAccountsForKeycard(keycard3.KeycardUID, []types.Address{addr}, 1003+uint64(i))
require.NoError(t, err)
}
rows, err = db.GetAllKnownKeycardsGroupedByKeyUID()
require.NoError(t, err)
// Test if correct keycard is deleted
deletedKeycard3 := true
for _, kp := range rows {
if kp.KeycardUID == keycard3.KeycardUID {
deletedKeycard3 = false
}
}
require.Equal(t, true, deletedKeycard3)
// Test update keycard uid
err = db.UpdateKeycardUID(keycard1.KeycardUID, keycardUID, 1100)
require.NoError(t, err)
// Test unlocking a locked keycard
err = db.KeycardUnlocked(keycardUID, 1101)
require.NoError(t, err)
rows, err = db.GetAllKnownKeycardsGroupedByKeyUID()
require.NoError(t, err)
locked = true
for _, kp := range rows {
if kp.KeycardUID == keycardUID {
locked = kp.KeycardLocked
}
}
require.Equal(t, false, locked)
require.True(t, SameKeycards(keycard1, dbKeycard1))
// Test detleting a keycard
err = db.DeleteKeycard(keycardUID, 1102)
err = db.DeleteKeycard(keycard1.KeycardUID, 1006)
require.NoError(t, err)
rows, err = db.GetAllKnownKeycardsGroupedByKeyUID()
dbKeycards, err = db.GetAllKnownKeycards()
require.NoError(t, err)
require.Equal(t, 1, len(rows))
// Test if correct keycard is deleted
deletedKeyCard := true
for _, kp := range rows {
if kp.KeycardUID == keycardUID {
deletedKeyCard = false
}
}
require.Equal(t, true, deletedKeyCard)
require.Equal(t, 2, len(dbKeycards))
dbKeycards, err = db.GetKeycardsWithSameKeyUID(keycard1.KeyUID)
require.NoError(t, err)
require.Equal(t, 0, len(dbKeycards))
dbKeycard, err := db.GetKeycardByKeycardUID(keycard1.KeycardUID)
require.Error(t, err)
require.True(t, err == ErrNoKeycardForPassedKeycardUID)
require.Nil(t, dbKeycard)
// Test detleting a keycard
err = db.DeleteAllKeycardsWithKeyUID(keycard2.KeyUID)
// Test detleting all keycards for KeyUID
dbKeycards, err = db.GetKeycardsWithSameKeyUID(keycard2.KeyUID)
require.NoError(t, err)
rows, err = db.GetAllKnownKeycardsGroupedByKeyUID()
require.Equal(t, 2, len(dbKeycards))
err = db.DeleteAllKeycardsWithKeyUID(keycard2.KeyUID, 1007)
require.NoError(t, err)
// Test if correct keycard is deleted
deletedKeycard2And3 := true
for _, kp := range rows {
if kp.KeyUID == keycard2.KeyUID {
deletedKeycard2And3 = false
}
}
require.Equal(t, true, deletedKeycard2And3)
dbKeycards, err = db.GetAllKnownKeycards()
require.NoError(t, err)
require.Equal(t, 0, len(dbKeycards))
dbKeycards, err = db.GetKeycardsWithSameKeyUID(keycard2.KeyUID)
require.NoError(t, err)
require.Equal(t, 0, len(dbKeycards))
dbKeycard, err = db.GetKeycardByKeycardUID(keycard2.KeycardUID)
require.Error(t, err)
require.True(t, err == ErrNoKeycardForPassedKeycardUID)
require.Nil(t, dbKeycard)
}
func TestKeycardsRemovalWhenDeletingKeypair(t *testing.T) {
db, stop := setupTestDB(t)
defer stop()
kp2 := &Keypair{
KeyUID: "0000000000000000000000000000000000000000000000000000000000000002",
Name: "Keypair Name 2",
Type: KeypairTypeSeed,
DerivedFrom: "0x0001",
}
kp2.Accounts = append(kp2.Accounts, &Account{Address: types.Address{0x11}, KeyUID: kp2.KeyUID})
kp2.Accounts = append(kp2.Accounts, &Account{Address: types.Address{0x12}, KeyUID: kp2.KeyUID})
kp2 := GetSeedImportedKeypair1ForTest()
keycard2 := GetKeycardForSeedImportedKeypair1ForTest()
keycard2 := Keycard{
KeycardUID: "00000000000000000000000000000002",
KeycardName: "Card02",
KeycardLocked: false,
AccountsAddresses: []types.Address{{0x11}, {0x12}},
KeyUID: kp2.KeyUID,
LastUpdateClock: 200,
}
keycard3 := Keycard{
KeycardUID: "00000000000000000000000000000003",
KeycardName: "Card02 Copy",
KeycardLocked: false,
AccountsAddresses: []types.Address{{0x11}, {0x12}},
KeyUID: kp2.KeyUID,
LastUpdateClock: 300,
}
keycard2Copy := GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
keycard2Copy.Position = keycard2Copy.Position + 1
// Pre-condition - save keypair
// Pre-condition
err := db.SaveOrUpdateKeypair(kp2)
require.NoError(t, err)
dbKeypairs, err := db.GetKeypairs()
@ -290,27 +173,24 @@ func TestKeycardsRemovalWhenDeletingKeypair(t *testing.T) {
require.Equal(t, 1, len(dbKeypairs))
// Pre-condition - save keycards referring to previously added keypair
addedKc, addedAccs, err := db.AddKeycardOrAddAccountsIfKeycardIsAdded(keycard2)
err = db.SaveOrUpdateKeycard(*keycard2, 0, false)
require.NoError(t, err)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
addedKc, addedAccs, err = db.AddKeycardOrAddAccountsIfKeycardIsAdded(keycard3)
dbKeycard2, err := db.GetKeycardByKeycardUID(keycard2.KeycardUID)
require.NoError(t, err)
require.Equal(t, true, addedKc)
require.Equal(t, false, addedAccs)
require.True(t, SameKeycards(keycard2, dbKeycard2))
err = db.SaveOrUpdateKeycard(*keycard2Copy, 0, false)
require.NoError(t, err)
dbKeycard2Copy, err := db.GetKeycardByKeycardUID(keycard2Copy.KeycardUID)
require.NoError(t, err)
require.True(t, SameKeycards(keycard2Copy, dbKeycard2Copy))
// Check db state
keycardsWithSameKeyUID, err := db.GetAllKnownKeycards()
dbKeycards, err := db.GetKeycardsWithSameKeyUID(keycard2.KeyUID)
require.NoError(t, err)
require.Equal(t, 2, len(keycardsWithSameKeyUID))
require.Equal(t, len(kp2.KeyUID), len(dbKeypairs[0].KeyUID))
require.Equal(t, len(kp2.KeyUID), len(keycardsWithSameKeyUID[0].KeyUID))
require.Equal(t, len(kp2.KeyUID), len(keycardsWithSameKeyUID[1].KeyUID))
require.Equal(t, len(kp2.Accounts), len(dbKeypairs[0].Accounts))
require.Equal(t, len(kp2.Accounts), len(keycardsWithSameKeyUID[0].AccountsAddresses))
require.Equal(t, len(kp2.Accounts), len(keycardsWithSameKeyUID[1].AccountsAddresses))
require.Equal(t, 2, len(dbKeycards))
require.True(t, Contains(dbKeycards, keycard2, SameKeycards))
require.True(t, Contains(dbKeycards, keycard2Copy, SameKeycards))
// Remove keypair
err = db.DeleteKeypair(kp2.KeyUID)
@ -321,7 +201,14 @@ func TestKeycardsRemovalWhenDeletingKeypair(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 0, len(dbKeypairs))
keycardsWithSameKeyUID, err = db.GetAllKnownKeycards()
dbKeycards, err = db.GetAllKnownKeycards()
require.NoError(t, err)
require.Equal(t, 0, len(keycardsWithSameKeyUID))
require.Equal(t, 0, len(dbKeycards))
dbKeycards, err = db.GetKeycardsWithSameKeyUID(kp2.KeyUID)
require.NoError(t, err)
require.Equal(t, 0, len(dbKeycards))
dbKeycard, err := db.GetKeycardByKeycardUID(keycard2.KeycardUID)
require.Error(t, err)
require.True(t, err == ErrNoKeycardForPassedKeycardUID)
require.Nil(t, dbKeycard)
}

View File

@ -257,7 +257,7 @@ func GetProfileKeycardForTest() *Keycard {
KeycardLocked: false,
AccountsAddresses: keycard1Addresses,
KeyUID: profileKp.KeyUID,
LastUpdateClock: 100,
Position: 0,
}
}
@ -273,7 +273,7 @@ func GetKeycardForSeedImportedKeypair1ForTest() *Keycard {
KeycardLocked: false,
AccountsAddresses: keycard2Addresses,
KeyUID: seed1Kp.KeyUID,
LastUpdateClock: 200,
Position: 1,
}
}
@ -289,10 +289,28 @@ func GetKeycardForSeedImportedKeypair2ForTest() *Keycard {
KeycardLocked: false,
AccountsAddresses: keycard4Addresses,
KeyUID: seed2Kp.KeyUID,
LastUpdateClock: 300,
Position: 2,
}
}
func Contains[T comparable](container []T, element T, isEqual func(T, T) bool) bool {
for _, e := range container {
if isEqual(e, element) {
return true
}
}
return false
}
func HaveSameElements[T comparable](a []T, b []T, isEqual func(T, T) bool) bool {
for _, v := range a {
if !Contains(b, v, isEqual) {
return false
}
}
return true
}
func SameAccounts(expected, real *Account) bool {
return expected.Address == real.Address &&
expected.KeyUID == real.KeyUID &&
@ -379,7 +397,7 @@ func SameKeycards(expected, real *Keycard) bool {
expected.KeyUID == real.KeyUID &&
expected.KeycardName == real.KeycardName &&
expected.KeycardLocked == real.KeycardLocked &&
expected.LastUpdateClock == real.LastUpdateClock &&
expected.Position == real.Position &&
len(expected.AccountsAddresses) == len(real.AccountsAddresses)
if same {

View File

@ -4315,20 +4315,6 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
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
}
case protobuf.SyncSocialLinks:
if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
logger.Warn("not coming from us, ignoring")

View File

@ -757,7 +757,7 @@ func (s *MessengerBackupSuite) TestBackupKeypairs() {
s.Require().Equal(accounts.SyncedFromBackup, dbProfileKp2.SyncedFrom)
for _, acc := range profileKp.Accounts {
s.Require().True(contains(dbProfileKp2.Accounts, acc, accounts.SameAccounts))
s.Require().True(accounts.Contains(dbProfileKp2.Accounts, acc, accounts.SameAccounts))
}
dbSeedKp2, err := bob2.settings.GetKeypairByKeyUID(seedKp.KeyUID)
@ -778,7 +778,6 @@ func (s *MessengerBackupSuite) TestBackupKeycards() {
keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1
kp3 := accounts.GetSeedImportedKeypair2ForTest()
keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest()
@ -794,22 +793,14 @@ func (s *MessengerBackupSuite) TestBackupKeycards() {
s.Require().NoError(err)
s.Require().Equal(3, len(dbKeypairs))
addedKc, addedAccs, err := bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = bob1.settings.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
addedKc, addedAccs, err = bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2)
err = bob1.settings.SaveOrUpdateKeycard(*keycard2, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
addedKc, addedAccs, err = bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy)
err = bob1.settings.SaveOrUpdateKeycard(*keycard2Copy, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
addedKc, addedAccs, err = bob1.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3)
err = bob1.settings.SaveOrUpdateKeycard(*keycard3, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Create bob2
bob2, err := newMessengerWithKey(s.shh, bob1.identity, s.logger, nil)
@ -835,10 +826,10 @@ func (s *MessengerBackupSuite) TestBackupKeycards() {
syncedKeycards, err := bob2.settings.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(4, len(syncedKeycards))
s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards))
s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards))
s.Require().True(contains(syncedKeycards, keycard2Copy, accounts.SameKeycards))
s.Require().True(contains(syncedKeycards, keycard3, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard1, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard2, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard2Copy, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard3, accounts.SameKeycards))
}
func (s *MessengerBackupSuite) TestBackupWatchOnlyAccounts() {

View File

@ -3036,13 +3036,13 @@ func (m *Messenger) resolveAccountOperability(syncAcc *protobuf.SyncAccount, syn
// We're here when we receive a keypair from the paired device which is either:
// 1. regular keypair or
// 2. was just converted from keycard to a regular keypair.
dbKeycardsForKeyUID, err := m.settings.GetKeycardByKeyUID(syncAcc.KeyUid)
if err != nil && err != accounts.ErrDbKeypairNotFound {
dbKeycardsForKeyUID, err := m.settings.GetKeycardsWithSameKeyUID(syncAcc.KeyUid)
if err != nil {
return accounts.AccountNonOperable, err
}
if len(dbKeycardsForKeyUID) > 0 {
// We're here in 2. case from above and in this case we need to mark all accounts for this keypair non operable
// We're here in case 2. from above and in this case we need to mark all accounts for this keypair non operable
return accounts.AccountNonOperable, nil
}
}
@ -3174,7 +3174,7 @@ func (m *Messenger) handleSyncKeypair(message *protobuf.SyncKeypair) (*accounts.
}
}
err = m.settings.DeleteKeypair(message.KeyUid)
err = m.settings.DeleteKeypair(message.KeyUid) // deleting keypair will delete related keycards as well
if err != nil && err != accounts.ErrDbKeypairNotFound {
return nil, err
}
@ -3192,13 +3192,12 @@ func (m *Messenger) handleSyncKeypair(message *protobuf.SyncKeypair) (*accounts.
for _, sKc := range message.Keycards {
kc := accounts.Keycard{}
kc.FromSyncKeycard(sKc)
kp.Keycards = append(kp.Keycards, &kc)
}
err = m.settings.ApplyKeycardsForKeypairWithKeyUID(kp.KeyUID, kp.Keycards)
err = m.settings.SaveOrUpdateKeycard(kc, message.Clock, false)
if err != nil {
return nil, err
}
kp.Keycards = append(kp.Keycards, &kc)
}
return kp, nil
}

View File

@ -3,24 +3,18 @@ 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/accounts"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
)
func (m *Messenger) prepareSyncKeycardsMessage(keyUID string) (message []*protobuf.SyncKeycard, err error) {
allKeycards, err := m.settings.GetAllKnownKeycards()
keycards, err := m.settings.GetKeycardsWithSameKeyUID(keyUID)
if err != nil {
return message, err
return
}
for _, kc := range allKeycards {
if kc.KeyUID != keyUID {
continue
}
for _, kc := range keycards {
syncKeycard := kc.ToSyncKeycard()
message = append(message, syncKeycard)
}
@ -28,198 +22,91 @@ func (m *Messenger) prepareSyncKeycardsMessage(keyUID string) (message []*protob
return
}
func (m *Messenger) dispatchKeycardActivity(ctx context.Context, syncMessage protobuf.SyncKeycardAction) error {
if !m.hasPairedDevices() {
return nil
}
func (m *Messenger) dispatchKeycardActivity(keyUID string, keycardUID string, newKeycardUID string, accountAddresses []types.Address,
callback func(uint64) error) error {
clock, _ := m.getLastClockWithRelatedChat()
clock, chat := m.getLastClockWithRelatedChat()
encodedMessage, err := proto.Marshal(&syncMessage)
finalKeyUID := keyUID
if finalKeyUID == "" {
dbKeycard, err := m.settings.GetKeycardByKeycardUID(keycardUID)
if err != nil {
return err
}
rawMessage := common.RawMessage{
LocalChatID: chat.ID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_SYNC_KEYCARD_ACTION,
ResendAutomatically: true,
finalKeyUID = dbKeycard.KeyUID
}
_, err = m.dispatchMessage(ctx, rawMessage)
if err != nil {
if err := callback(clock); err != nil {
return err
}
chat.LastClockValue = clock
return m.saveChat(chat)
return m.resolveAndSyncKeypairOrJustWalletAccount(finalKeyUID, types.Address{}, clock, m.dispatchMessage)
}
func (m *Messenger) handleSyncKeycardActivity(state *ReceivedMessageState, syncMessage protobuf.SyncKeycardAction) (err error) {
var kcAction = &accounts.KeycardAction{
Action: protobuf.SyncKeycardAction_Action_name[int32(syncMessage.Action)],
OldKeycardUID: syncMessage.OldKeycardUid,
Keycard: &accounts.Keycard{},
}
kcAction.Keycard.FromSyncKeycard(syncMessage.Keycard)
switch syncMessage.Action {
case protobuf.SyncKeycardAction_KEYCARD_ADDED,
protobuf.SyncKeycardAction_ACCOUNTS_ADDED:
_, _, err = m.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*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 {
// This function stores keycard to db and notifies paired devices about that if keycard with `KeycardUID` is not already stored.
// Keycard position is fully maintained by the backend.
// If keycard is already stored, this function updates `KeycardName` and adds accounts which are not already added, in this case
// `KeycardLocked` and `Position` remains as they were, they won't be changed.
func (m *Messenger) SaveOrUpdateKeycard(ctx context.Context, keycard *accounts.Keycard) (err error) {
dbKeycard, err := m.settings.GetKeycardByKeycardUID(keycard.KeycardUID)
if err != nil && err != accounts.ErrNoKeycardForPassedKeycardUID {
return err
}
state.Response.AddKeycardAction(kcAction)
return nil
}
func (m *Messenger) AddKeycardOrAddAccountsIfKeycardIsAdded(ctx context.Context, kp *accounts.Keycard) (added bool, err error) {
addedKc, addedAccs, err := m.settings.AddKeycardOrAddAccountsIfKeycardIsAdded(*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, addresses []types.Address, clock uint64) error {
err := m.settings.RemoveMigratedAccountsForKeycard(kcUID, addresses, clock)
if dbKeycard == nil {
position, err := m.settings.GetPositionForNextNewKeycard()
if err != nil {
return err
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_ACCOUNTS_REMOVED,
Keycard: &protobuf.SyncKeycard{
Uid: kcUID,
Clock: clock,
},
keycard.Position = position
keycard.KeycardLocked = false
} else {
keycard.Position = dbKeycard.Position
keycard.KeycardLocked = dbKeycard.KeycardLocked
}
for _, addr := range addresses {
activityMessage.Keycard.Addresses = append(activityMessage.Keycard.Addresses, addr.Bytes())
return m.dispatchKeycardActivity(keycard.KeyUID, "", "", []types.Address{}, func(clock uint64) error {
return m.settings.SaveOrUpdateKeycard(*keycard, clock, true)
})
}
return m.dispatchKeycardActivity(ctx, activityMessage)
func (m *Messenger) SetKeycardName(ctx context.Context, keycardUID string, kpName string) error {
return m.dispatchKeycardActivity("", keycardUID, "", []types.Address{}, func(clock uint64) error {
return m.settings.SetKeycardName(keycardUID, kpName, clock)
})
}
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
func (m *Messenger) KeycardLocked(ctx context.Context, keycardUID string) error {
return m.dispatchKeycardActivity("", keycardUID, "", []types.Address{}, func(clock uint64) error {
return m.settings.KeycardLocked(keycardUID, clock)
})
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_NAME_CHANGED,
Keycard: &protobuf.SyncKeycard{
Uid: kcUID,
Name: kpName,
Clock: clock,
},
func (m *Messenger) KeycardUnlocked(ctx context.Context, keycardUID string) error {
return m.dispatchKeycardActivity("", keycardUID, "", []types.Address{}, func(clock uint64) error {
return m.settings.KeycardUnlocked(keycardUID, clock)
})
}
return m.dispatchKeycardActivity(ctx, activityMessage)
func (m *Messenger) DeleteKeycardAccounts(ctx context.Context, keycardUID string, accountAddresses []types.Address) error {
return m.dispatchKeycardActivity("", keycardUID, "", accountAddresses, func(clock uint64) error {
return m.settings.DeleteKeycardAccounts(keycardUID, accountAddresses, clock)
})
}
func (m *Messenger) KeycardLocked(ctx context.Context, kcUID string, clock uint64) error {
err := m.settings.KeycardLocked(kcUID, clock)
if err != nil {
return err
func (m *Messenger) DeleteKeycard(ctx context.Context, keycardUID string) error {
return m.dispatchKeycardActivity("", keycardUID, "", []types.Address{}, func(clock uint64) error {
return m.settings.DeleteKeycard(keycardUID, clock)
})
}
activityMessage := protobuf.SyncKeycardAction{
Action: protobuf.SyncKeycardAction_LOCKED,
Keycard: &protobuf.SyncKeycard{
Uid: kcUID,
Clock: clock,
},
func (m *Messenger) DeleteAllKeycardsWithKeyUID(ctx context.Context, keyUID string) error {
return m.dispatchKeycardActivity(keyUID, "", "", []types.Address{}, func(clock uint64) error {
return m.settings.DeleteAllKeycardsWithKeyUID(keyUID, 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)
func (m *Messenger) UpdateKeycardUID(ctx context.Context, oldKeycardUID string, newKeycardUID string) error {
return m.dispatchKeycardActivity("", oldKeycardUID, newKeycardUID, []types.Address{}, func(clock uint64) error {
return m.settings.UpdateKeycardUID(oldKeycardUID, newKeycardUID, clock)
})
}

View File

@ -74,7 +74,6 @@ type MessengerResponse struct {
trustStatus map[string]verification.TrustStatus
emojiReactions map[string]*EmojiReaction
savedAddresses map[string]*wallet.SavedAddress
keycardActions []*accounts.KeycardAction
SocialLinksInfo *identity.SocialLinksInfo
ensUsernameDetails []*ensservice.UsernameDetail
}
@ -116,7 +115,6 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
DiscordMessages []*protobuf.DiscordMessage `json:"discordMessages,omitempty"`
DiscordMessageAttachments []*protobuf.DiscordMessageAttachment `json:"discordMessageAtachments,omitempty"`
SavedAddresses []*wallet.SavedAddress `json:"savedAddresses,omitempty"`
KeycardActions []*accounts.KeycardAction `json:"keycardActions,omitempty"`
SocialLinksInfo *identity.SocialLinksInfo `json:"socialLinksInfo,omitempty"`
EnsUsernameDetails []*ensservice.UsernameDetail `json:"ensUsernameDetails,omitempty"`
}{
@ -151,7 +149,6 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
DiscordCategories: r.DiscordCategories,
DiscordChannels: r.DiscordChannels,
DiscordOldestMessageTimestamp: r.DiscordOldestMessageTimestamp,
KeycardActions: r.KeycardActions(),
SocialLinksInfo: r.SocialLinksInfo,
EnsUsernameDetails: r.EnsUsernameDetails(),
}
@ -279,7 +276,6 @@ func (r *MessengerResponse) IsEmpty() bool {
len(r.verificationRequests)+
len(r.RequestsToJoinCommunity)+
len(r.savedAddresses)+
len(r.keycardActions) == 0 &&
len(r.ensUsernameDetails) == 0 &&
r.currentStatus == nil &&
r.activityCenterState == nil &&
@ -312,7 +308,6 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error {
r.AddEmojiReactions(response.EmojiReactions())
r.AddInstallations(response.Installations)
r.AddSavedAddresses(response.SavedAddresses())
r.AddKeycardActions(response.KeycardActions())
r.AddEnsUsernameDetails(response.EnsUsernameDetails())
r.AddRequestsToJoinCommunity(response.RequestsToJoinCommunity)
r.AddBookmarks(response.GetBookmarks())
@ -463,18 +458,6 @@ func (r *MessengerResponse) SavedAddresses() []*wallet.SavedAddress {
return ers
}
func (r *MessengerResponse) AddKeycardAction(keycardAction *accounts.KeycardAction) {
r.keycardActions = append(r.keycardActions, keycardAction)
}
func (r *MessengerResponse) AddKeycardActions(keycardActions []*accounts.KeycardAction) {
r.keycardActions = append(r.keycardActions, keycardActions...)
}
func (r *MessengerResponse) KeycardActions() []*accounts.KeycardAction {
return r.keycardActions
}
func (r *MessengerResponse) AddEnsUsernameDetail(detail *ensservice.UsernameDetail) {
r.ensUsernameDetails = append(r.ensUsernameDetails, detail)
}

View File

@ -79,6 +79,9 @@ func (s *MessengerSyncKeycardChangeSuite) SetupTest() {
kp1 := accounts.GetProfileKeypairForTest(true, true, true)
kp2 := accounts.GetSeedImportedKeypair1ForTest()
// kp3 := accounts.GetSeedImportedKeypair2ForTest()
kp1.Clock = 1
kp2.Clock = 1
// kp3.Clock = 1
err = s.main.settings.SaveOrUpdateKeypair(kp1)
s.Require().NoError(err)
@ -90,11 +93,15 @@ func (s *MessengerSyncKeycardChangeSuite) SetupTest() {
s.Require().NoError(err)
s.Require().Equal(2, len(dbKeypairs))
err = s.other.SaveOrUpdateKeypair(kp1)
kp1.Clock = 0
kp2.Clock = 0
// kp3.Clock = 0
err = s.other.settings.SaveOrUpdateKeypair(kp1)
s.Require().NoError(err)
err = s.other.SaveOrUpdateKeypair(kp2)
err = s.other.settings.SaveOrUpdateKeypair(kp2)
s.Require().NoError(err)
// err = s.other.SaveOrUpdateKeypair(kp3)
// err = s.other.settings.SaveOrUpdateKeypair(kp3)
// s.Require().NoError(err)
dbKeypairs, err = s.other.settings.GetKeypairs()
s.Require().NoError(err)
@ -124,19 +131,16 @@ func (s *MessengerSyncKeycardChangeSuite) TestAddingNewKeycards() {
keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
added, err := s.main.AddKeycardOrAddAccountsIfKeycardIsAdded(context.Background(), keycard1)
err := s.main.SaveOrUpdateKeycard(context.Background(), keycard1)
s.Require().NoError(err)
s.Require().Equal(true, added)
added, err = s.main.AddKeycardOrAddAccountsIfKeycardIsAdded(context.Background(), keycard2)
err = s.main.SaveOrUpdateKeycard(context.Background(), keycard2)
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()) == 2
return len(r.Keypairs) == 2
},
"expected to receive keycard activities",
)
@ -145,14 +149,14 @@ func (s *MessengerSyncKeycardChangeSuite) TestAddingNewKeycards() {
senderKeycards, err := s.main.settings.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(2, len(senderKeycards))
s.Require().True(contains(senderKeycards, keycard1, accounts.SameKeycards))
s.Require().True(contains(senderKeycards, keycard2, accounts.SameKeycards))
s.Require().True(accounts.Contains(senderKeycards, keycard1, accounts.SameKeycards))
s.Require().True(accounts.Contains(senderKeycards, keycard2, accounts.SameKeycards))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(2, len(syncedKeycards))
s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards))
s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard1, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard2, accounts.SameKeycards))
}
func (s *MessengerSyncKeycardChangeSuite) TestAddingAccountsToKeycard() {
@ -164,27 +168,22 @@ func (s *MessengerSyncKeycardChangeSuite) TestAddingAccountsToKeycard() {
keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add additional accounts to sender
added, err := s.main.AddKeycardOrAddAccountsIfKeycardIsAdded(context.Background(), keycard2)
err = s.main.SaveOrUpdateKeycard(context.Background(), keycard2)
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()) == 1
return len(r.Keypairs) == 1
},
"expected to receive keycard activities",
)
@ -210,31 +209,26 @@ func (s *MessengerSyncKeycardChangeSuite) TestRemovingAccountsFromKeycard() {
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.AccountsAddresses = updatedKeycard1.AccountsAddresses[2:]
// Remove accounts from sender
err = s.main.RemoveMigratedAccountsForKeycard(context.Background(), keycard1.KeycardUID,
keycard1.AccountsAddresses[:2], updatedKeycard1.LastUpdateClock)
err = s.main.DeleteKeycardAccounts(context.Background(), keycard1.KeycardUID, keycard1.AccountsAddresses[:2])
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
return len(r.Keypairs) == 1
},
"expected to receive keycard activities",
)
@ -251,44 +245,39 @@ func (s *MessengerSyncKeycardChangeSuite) TestRemovingAccountsFromKeycard() {
s.Require().True(contains(syncedKeycards, updatedKeycard1, accounts.SameKeycards))
}
func (s *MessengerSyncKeycardChangeSuite) TestRemovingAllAccountsFromKeycard() {
func (s *MessengerSyncKeycardChangeSuite) TestRemovingAllAccountsForKeyUID() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Remove all accounts from sender
err = s.main.RemoveMigratedAccountsForKeycard(context.Background(), keycard1.KeycardUID,
keycard1.AccountsAddresses, keycard1.LastUpdateClock)
// Remove all accounts from sender for KeyUID
err = s.main.DeleteAllKeycardsWithKeyUID(context.Background(), keycard1.KeyUID)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
return len(r.Keypairs) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
senderKeycards, err := senderDb.GetAllKnownKeycards()
senderKeycards, err := senderDb.GetKeycardsWithSameKeyUID(keycard1.KeyUID)
s.Require().NoError(err)
s.Require().Equal(0, len(senderKeycards))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
syncedKeycards, err := dbOnReceiver.GetKeycardsWithSameKeyUID(keycard1.KeyUID)
s.Require().NoError(err)
s.Require().Equal(0, len(syncedKeycards))
}
@ -300,38 +289,36 @@ func (s *MessengerSyncKeycardChangeSuite) TestDeleteKeycard() {
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Remove keycard from sender
err = s.main.DeleteKeycard(context.Background(), keycard1.KeycardUID, keycard1.LastUpdateClock)
err = s.main.DeleteKeycard(context.Background(), keycard1.KeycardUID)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
return len(r.Keypairs) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
senderKeycards, err := senderDb.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(0, len(senderKeycards))
senderKeycard, err := senderDb.GetKeycardByKeycardUID(keycard1.KeycardUID)
s.Require().Error(err)
s.Require().True(err == accounts.ErrNoKeycardForPassedKeycardUID)
s.Require().Nil(senderKeycard)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(0, len(syncedKeycards))
syncedKeycard, err := dbOnReceiver.GetKeycardByKeycardUID(keycard1.KeycardUID)
s.Require().Error(err)
s.Require().True(err == accounts.ErrNoKeycardForPassedKeycardUID)
s.Require().Nil(syncedKeycard)
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardName() {
@ -341,94 +328,38 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardName() {
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.KeycardName = "New Keycard Name"
// Set new keycard name to sender
err = s.main.SetKeycardName(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.KeycardName,
updatedKeycard1.LastUpdateClock)
err = s.main.SetKeycardName(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.KeycardName)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
return len(r.Keypairs) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
senderKeycards, err := senderDb.GetAllKnownKeycards()
senderKeycard, err := senderDb.GetKeycardByKeycardUID(updatedKeycard1.KeycardUID)
s.Require().NoError(err)
s.Require().Equal(1, len(senderKeycards))
s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycards[0]))
s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycard))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
syncedKeycard, err := dbOnReceiver.GetKeycardByKeycardUID(updatedKeycard1.KeycardUID)
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardNameWithOlderClock() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.KeycardName = "New Keycard Name"
updatedKeycard1.LastUpdateClock = updatedKeycard1.LastUpdateClock - 1
// Set new keycard name to sender
err = s.main.SetKeycardName(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.KeycardName,
updatedKeycard1.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)
senderKeycards, err := senderDb.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(senderKeycards))
s.Require().True(accounts.SameKeycards(keycard1, senderKeycards[0]))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(accounts.SameKeycards(keycard1, syncedKeycards[0]))
s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycard))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLocked() {
@ -438,90 +369,37 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLocked() {
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.KeycardLocked = true
err = s.main.KeycardLocked(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.LastUpdateClock)
err = s.main.KeycardLocked(context.Background(), updatedKeycard1.KeycardUID)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
return len(r.Keypairs) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
senderKeycards, err := senderDb.GetAllKnownKeycards()
senderKeycard, err := senderDb.GetKeycardByKeycardUID(updatedKeycard1.KeycardUID)
s.Require().NoError(err)
s.Require().Equal(1, len(senderKeycards))
s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycards[0]))
s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycard))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
syncedKeycard, err := dbOnReceiver.GetKeycardByKeycardUID(updatedKeycard1.KeycardUID)
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardLockedOlderClock() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.KeycardLocked = true
updatedKeycard1.LastUpdateClock = updatedKeycard1.LastUpdateClock - 1
err = s.main.KeycardLocked(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.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)
senderKeycards, err := senderDb.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(senderKeycards))
s.Require().True(accounts.SameKeycards(keycard1, senderKeycards[0]))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(accounts.SameKeycards(keycard1, syncedKeycards[0]))
s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycard))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlocked() {
@ -532,91 +410,37 @@ func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlocked() {
keycard1.KeycardLocked = true
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.KeycardLocked = false
err = s.main.KeycardUnlocked(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.LastUpdateClock)
err = s.main.KeycardUnlocked(context.Background(), updatedKeycard1.KeycardUID)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
return len(r.Keypairs) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
senderKeycards, err := senderDb.GetAllKnownKeycards()
senderKeycard, err := senderDb.GetKeycardByKeycardUID(updatedKeycard1.KeycardUID)
s.Require().NoError(err)
s.Require().Equal(1, len(senderKeycards))
s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycards[0]))
s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycard))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
syncedKeycard, err := dbOnReceiver.GetKeycardByKeycardUID(updatedKeycard1.KeycardUID)
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestSettingKeycardUnlockedOlderClock() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
keycard1 := accounts.GetProfileKeycardForTest()
keycard1.KeycardLocked = true
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.KeycardLocked = false
updatedKeycard1.LastUpdateClock = updatedKeycard1.LastUpdateClock - 1
err = s.main.KeycardUnlocked(context.Background(), updatedKeycard1.KeycardUID, updatedKeycard1.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)
senderKeycards, err := senderDb.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(senderKeycards))
s.Require().True(accounts.SameKeycards(keycard1, senderKeycards[0]))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(accounts.SameKeycards(keycard1, syncedKeycards[0]))
s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycard))
}
func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUid() {
@ -626,92 +450,36 @@ func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUid() {
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.KeycardUID = "00000000000000000000000000000000"
// Update keycard uid on sender
err = s.main.UpdateKeycardUID(context.Background(), keycard1.KeycardUID, updatedKeycard1.KeycardUID,
updatedKeycard1.LastUpdateClock)
err = s.main.UpdateKeycardUID(context.Background(), keycard1.KeycardUID, updatedKeycard1.KeycardUID)
s.Require().NoError(err)
// Wait for the response
_, err = WaitOnMessengerResponse(
s.other,
func(r *MessengerResponse) bool {
return len(r.KeycardActions()) == 1
return len(r.Keypairs) == 1
},
"expected to receive keycard activities",
)
s.Require().NoError(err)
senderKeycards, err := senderDb.GetAllKnownKeycards()
senderKeycard, err := senderDb.GetKeycardByKeycardUID(updatedKeycard1.KeycardUID)
s.Require().NoError(err)
s.Require().Equal(1, len(senderKeycards))
s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycards[0]))
s.Require().True(accounts.SameKeycards(updatedKeycard1, senderKeycard))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
syncedKeycard, err := dbOnReceiver.GetKeycardByKeycardUID(updatedKeycard1.KeycardUID)
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycards[0]))
}
func (s *MessengerSyncKeycardChangeSuite) TestUpdatingKeycardUidOldClock() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
keycard1 := accounts.GetProfileKeycardForTest()
// Add keycard on sender
addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Add the same keycard on receiver
addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
s.Require().NoError(err)
s.Require().Equal(true, addedKc)
s.Require().Equal(false, addedAccs)
// Prepare expected keycard for comparison
updatedKeycard1 := accounts.GetProfileKeycardForTest()
updatedKeycard1.KeycardUID = "00000000000000000000000000000000"
updatedKeycard1.LastUpdateClock = updatedKeycard1.LastUpdateClock - 1
// Update keycard uid on sender
err = s.main.UpdateKeycardUID(context.Background(), keycard1.KeycardUID, updatedKeycard1.KeycardUID,
updatedKeycard1.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)
senderKeycards, err := senderDb.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(senderKeycards))
s.Require().True(accounts.SameKeycards(keycard1, senderKeycards[0]))
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(1, len(syncedKeycards))
s.Require().True(accounts.SameKeycards(keycard1, syncedKeycards[0]))
s.Require().True(accounts.SameKeycards(updatedKeycard1, syncedKeycard))
}

View File

@ -79,6 +79,9 @@ func (s *MessengerSyncKeycardsStateSuite) SetupTest() {
kp1 := accounts.GetProfileKeypairForTest(true, true, true)
kp2 := accounts.GetSeedImportedKeypair1ForTest()
kp3 := accounts.GetSeedImportedKeypair2ForTest()
kp1.Clock = 1
kp2.Clock = 1
kp3.Clock = 1
err = s.main.settings.SaveOrUpdateKeypair(kp1)
s.Require().NoError(err)
@ -90,11 +93,15 @@ func (s *MessengerSyncKeycardsStateSuite) SetupTest() {
s.Require().NoError(err)
s.Require().Equal(3, len(dbKeypairs))
err = s.other.SaveOrUpdateKeypair(kp1)
kp1.Clock = 0
kp2.Clock = 0
kp3.Clock = 0
err = s.other.settings.SaveOrUpdateKeypair(kp1)
s.Require().NoError(err)
err = s.other.SaveOrUpdateKeypair(kp2)
err = s.other.settings.SaveOrUpdateKeypair(kp2)
s.Require().NoError(err)
err = s.other.SaveOrUpdateKeypair(kp3)
err = s.other.settings.SaveOrUpdateKeypair(kp3)
s.Require().NoError(err)
dbKeypairs, err = s.other.settings.GetKeypairs()
s.Require().NoError(err)
@ -116,338 +123,173 @@ func (s *MessengerSyncKeycardsStateSuite) newMessenger(shh types.Waku) *Messenge
return messenger
}
// TODO: commented tests below will be handled in the seocnd step of planned improvements
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNoKeycards() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasNoKeycards() {
// senderDb := s.main.settings
// dbOnReceiver := s.other.settings
keycard1 := accounts.GetProfileKeycardForTest()
// keycard1 := accounts.GetProfileKeycardForTest()
keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
// keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
// keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
// keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1
keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest()
// keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest()
// Add keycards on sender
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
err = senderDb.SaveOrUpdateKeycard(*keycard2, 0, false)
s.Require().NoError(err)
err = senderDb.SaveOrUpdateKeycard(*keycard2Copy, 0, false)
s.Require().NoError(err)
err = senderDb.SaveOrUpdateKeycard(*keycard3, 0, false)
s.Require().NoError(err)
// // Add keycards on sender
// addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3)
// 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)
// // 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 {
success := len(r.Keypairs) == 3
for _, kp := range r.Keypairs {
if kp.KeyUID == keycard1.KeyUID {
success = success && len(kp.Keycards) == 1
} else if kp.KeyUID == keycard2.KeyUID {
success = success && len(kp.Keycards) == 2
} else if kp.KeyUID == keycard3.KeyUID {
success = success && len(kp.Keycards) == 1
}
}
return success
},
"expected to receive keycards",
)
s.Require().NoError(err)
// // Wait for the response
// _, err = WaitOnMessengerResponse(
// s.other,
// func(r *MessengerResponse) bool {
// success := len(r.Keypairs) == 3
// for _, kp := range r.Keypairs {
// if kp.KeyUID == keycard1.KeyUID {
// success = success && len(kp.Keycards) == 1
// } else if kp.KeyUID == keycard2.KeyUID {
// success = success && len(kp.Keycards) == 2
// } else if kp.KeyUID == keycard3.KeyUID {
// success = success && len(kp.Keycards) == 1
// }
// }
// return success
// },
// "expected to receive keycards",
// )
// s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(4, len(syncedKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard1, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard2, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard2Copy, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard3, accounts.SameKeycards))
}
// syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
// s.Require().NoError(err)
// s.Require().Equal(4, len(syncedKeycards))
// s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards))
// s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards))
// s.Require().True(contains(syncedKeycards, keycard2Copy, accounts.SameKeycards))
// s.Require().True(contains(syncedKeycards, keycard3, accounts.SameKeycards))
// }
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfKeycardsWereDeletedOnSenderSide() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasKeycardsOlderThanSender() {
// senderDb := s.main.settings
// dbOnReceiver := s.other.settings
// Add keycards on sender
keycard1 := accounts.GetProfileKeycardForTest()
// keycard1 := accounts.GetProfileKeycardForTest()
keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
// // Add keycards on sender
// addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest()
// // Add keycards on receiver - partially
// keycardR1 := accounts.GetProfileKeycardForTest()
// keycardR1.KeycardName = "CardNameToBeChanged-0"
// keycardR1.AccountsAddresses = keycardR1.AccountsAddresses[2:3]
// keycardR1.LastUpdateClock = keycardR1.LastUpdateClock - 1
// Add keycards on sender
err := senderDb.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
err = senderDb.SaveOrUpdateKeycard(*keycard2, 0, false)
s.Require().NoError(err)
// keycardR2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycardR2.KeycardName = "CardNameToBeChanged-1"
// keycardR2.LastUpdateClock = keycardR2.LastUpdateClock - 1
// Add keycards on receiver
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard2, 0, false)
s.Require().NoError(err)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard2Copy, 0, false)
s.Require().NoError(err)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard3, 0, false)
s.Require().NoError(err)
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardR1)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardR2)
// 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)
// // 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 {
success := len(r.Keypairs) == 3
for _, kp := range r.Keypairs {
if kp.KeyUID == keycard1.KeyUID {
success = success && len(kp.Keycards) == 1
} else if kp.KeyUID == keycard2.KeyUID {
success = success && len(kp.Keycards) == 1
}
}
return success
},
"expected to receive keycards",
)
s.Require().NoError(err)
// // Wait for the response
// _, err = WaitOnMessengerResponse(
// s.other,
// func(r *MessengerResponse) bool {
// success := len(r.Keypairs) == 3
// for _, kp := range r.Keypairs {
// if kp.KeyUID == keycardR1.KeyUID {
// success = success && len(kp.Keycards) == 1
// } else if kp.KeyUID == keycardR2.KeyUID {
// success = success && len(kp.Keycards) == 1
// }
// }
// return success
// },
// "expected to receive keycards",
// )
// s.Require().NoError(err)
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(2, len(syncedKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard1, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard2, accounts.SameKeycards))
}
// syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
// s.Require().NoError(err)
// s.Require().Equal(2, len(syncedKeycards))
// s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards))
// s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards))
// }
func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverAndSenderHasNoKeycardsInCommon() {
senderDb := s.main.settings
dbOnReceiver := s.other.settings
// func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverHasKeycardsNewerThanSender() {
// senderDb := s.main.settings
// dbOnReceiver := s.other.settings
// Add keycards on sender
keycard1 := accounts.GetProfileKeycardForTest()
// keycard1 := accounts.GetProfileKeycardForTest()
keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest()
keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
// // Add keycards on sender
// addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest()
// // Add keycards on receiver - partially
// keycardR1 := accounts.GetProfileKeycardForTest()
// keycardR1.KeycardName = "CardNameToBeChanged-0"
// keycardR1.AccountsAddresses = keycardR1.AccountsAddresses[2:3]
// keycardR1.LastUpdateClock = keycardR1.LastUpdateClock + 1
// Add keycards on sender
err := senderDb.SaveOrUpdateKeycard(*keycard2, 0, false)
s.Require().NoError(err)
err = senderDb.SaveOrUpdateKeycard(*keycard2Copy, 0, false)
s.Require().NoError(err)
// keycardR2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycardR2.KeycardName = "CardNameToBeChanged-1"
// keycardR2.LastUpdateClock = keycardR2.LastUpdateClock + 1
// Add keycards on receiver
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard1, 0, false)
s.Require().NoError(err)
err = dbOnReceiver.SaveOrUpdateKeycard(*keycard3, 0, false)
s.Require().NoError(err)
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardR1)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycardR2)
// 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)
// // 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 {
success := len(r.Keypairs) == 3
for _, kp := range r.Keypairs {
if kp.KeyUID == keycard2.KeyUID {
success = success && len(kp.Keycards) == 2
}
}
return success
},
"expected to receive keycards",
)
s.Require().NoError(err)
// // Wait for the response
// _, err = WaitOnMessengerResponse(
// s.other,
// func(r *MessengerResponse) bool {
// success := len(r.Keypairs) == 3
// for _, kp := range r.Keypairs {
// if kp.KeyUID == keycardR1.KeyUID {
// success = success && len(kp.Keycards) == 1
// } else if kp.KeyUID == keycardR2.KeyUID {
// success = success && len(kp.Keycards) == 1
// }
// }
// return success
// },
// "expected to receive keycards",
// )
// s.Require().NoError(err)
// syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
// s.Require().NoError(err)
// s.Require().Equal(2, len(syncedKeycards))
// s.Require().True(contains(syncedKeycards, keycardR1, accounts.SameKeycards))
// s.Require().True(contains(syncedKeycards, keycardR2, accounts.SameKeycards))
// }
// func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfKeycardsWereDeletedOnSenderSide() {
// senderDb := s.main.settings
// dbOnReceiver := s.other.settings
// // Add keycards on sender
// keycard1 := accounts.GetProfileKeycardForTest()
// keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
// keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
// keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1
// keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest()
// // Add keycards on sender
// addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// // Add keycards on receiver
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3)
// 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 {
// success := len(r.Keypairs) == 3
// for _, kp := range r.Keypairs {
// if kp.KeyUID == keycard1.KeyUID {
// success = success && len(kp.Keycards) == 1
// } else if kp.KeyUID == keycard2.KeyUID {
// success = success && len(kp.Keycards) == 1
// }
// }
// return success
// },
// "expected to receive keycards",
// )
// s.Require().NoError(err)
// syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
// s.Require().NoError(err)
// s.Require().Equal(2, len(syncedKeycards))
// s.Require().True(contains(syncedKeycards, keycard1, accounts.SameKeycards))
// s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards))
// }
// func (s *MessengerSyncKeycardsStateSuite) TestSyncKeycardsIfReceiverAndSenderHasNoKeycardsInCommon() {
// senderDb := s.main.settings
// dbOnReceiver := s.other.settings
// // Add keycards on sender
// keycard1 := accounts.GetProfileKeycardForTest()
// keycard2 := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycard2Copy := accounts.GetKeycardForSeedImportedKeypair1ForTest()
// keycard2Copy.KeycardUID = keycard2Copy.KeycardUID + "C"
// keycard2Copy.KeycardName = keycard2Copy.KeycardName + "Copy"
// keycard2Copy.LastUpdateClock = keycard2Copy.LastUpdateClock + 1
// keycard3 := accounts.GetKeycardForSeedImportedKeypair2ForTest()
// // Add keycards on sender
// addedKc, addedAccs, err := senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = senderDb.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard2Copy)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// // Add keycards on receiver
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard1)
// s.Require().NoError(err)
// s.Require().Equal(true, addedKc)
// s.Require().Equal(false, addedAccs)
// addedKc, addedAccs, err = dbOnReceiver.AddKeycardOrAddAccountsIfKeycardIsAdded(*keycard3)
// 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 {
// success := len(r.Keypairs) == 3
// for _, kp := range r.Keypairs {
// if kp.KeyUID == keycard2.KeyUID {
// success = success && len(kp.Keycards) == 2
// }
// }
// return success
// },
// "expected to receive keycards",
// )
// s.Require().NoError(err)
// syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
// s.Require().NoError(err)
// s.Require().Equal(2, len(syncedKeycards))
// s.Require().True(contains(syncedKeycards, keycard2, accounts.SameKeycards))
// s.Require().True(contains(syncedKeycards, keycard2Copy, accounts.SameKeycards))
// }
syncedKeycards, err := dbOnReceiver.GetAllKnownKeycards()
s.Require().NoError(err)
s.Require().Equal(2, len(syncedKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard2, accounts.SameKeycards))
s.Require().True(accounts.Contains(syncedKeycards, keycard2Copy, accounts.SameKeycards))
}

View File

@ -198,7 +198,7 @@ func (m *Messenger) deleteKeystoreFileForAddress(address types.Address) error {
lastAcccountOfKeypairWithTheSameKey := len(kp.Accounts) == 1
knownKeycardsForKeyUID, err := m.settings.GetKeycardByKeyUID(acc.KeyUID)
knownKeycardsForKeyUID, err := m.settings.GetKeycardsWithSameKeyUID(acc.KeyUID)
if err != nil {
return err
}
@ -219,23 +219,6 @@ func (m *Messenger) deleteKeystoreFileForAddress(address types.Address) error {
}
}
}
} else {
if lastAcccountOfKeypairWithTheSameKey {
knownKeycards, err := m.settings.GetAllKnownKeycards()
if err != nil {
return err
}
for _, kc := range knownKeycards {
if kc.KeyUID == acc.KeyUID {
clock := uint64(time.Now().Unix())
err = m.RemoveMigratedAccountsForKeycard(context.Background(), kc.KeycardUID, kc.AccountsAddresses, clock)
if err != nil {
return err
}
}
}
}
}
}

View File

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

View File

@ -75,12 +75,11 @@ message ApplicationMetadataMessage {
COMMUNITY_CANCEL_REQUEST_TO_JOIN = 60;
CANCEL_CONTACT_VERIFICATION = 61;
SYNC_KEYPAIR = 62;
SYNC_KEYCARD_ACTION = 63;
SYNC_SOCIAL_LINKS = 64;
SYNC_ENS_USERNAME_DETAIL = 65;
SYNC_ACTIVITY_CENTER_NOTIFICATION = 66;
SYNC_ACTIVITY_CENTER_NOTIFICATION_STATE = 67;
COMMUNITY_ADMIN_MESSAGE = 68;
COMMUNITY_EDIT_SHARED_ADDRESSES = 69;
SYNC_SOCIAL_LINKS = 63;
SYNC_ENS_USERNAME_DETAIL = 64;
SYNC_ACTIVITY_CENTER_NOTIFICATION = 65;
SYNC_ACTIVITY_CENTER_NOTIFICATION_STATE = 66;
COMMUNITY_ADMIN_MESSAGE = 67;
COMMUNITY_EDIT_SHARED_ADDRESSES = 68;
}
}

View File

@ -230,49 +230,6 @@ func (SyncContactRequestDecision_DecisionStatus) EnumDescriptor() ([]byte, []int
return fileDescriptor_d61ab7221f0b5518, []int{32, 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{37, 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"`
@ -3214,7 +3171,7 @@ type SyncKeycard struct {
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"`
Position uint64 `protobuf:"varint,6,opt,name=position,proto3" json:"position,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -3280,68 +3237,13 @@ func (m *SyncKeycard) GetAddresses() [][]byte {
return nil
}
func (m *SyncKeycard) GetClock() uint64 {
func (m *SyncKeycard) GetPosition() uint64 {
if m != nil {
return m.Clock
return m.Position
}
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{37}
}
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 SyncSocialLinks struct {
SocialLinks []*SocialLink `protobuf:"bytes,1,rep,name=social_links,json=socialLinks,proto3" json:"social_links,omitempty"`
Clock uint64 `protobuf:"varint,2,opt,name=clock,proto3" json:"clock,omitempty"`
@ -3354,7 +3256,7 @@ func (m *SyncSocialLinks) Reset() { *m = SyncSocialLinks{} }
func (m *SyncSocialLinks) String() string { return proto.CompactTextString(m) }
func (*SyncSocialLinks) ProtoMessage() {}
func (*SyncSocialLinks) Descriptor() ([]byte, []int) {
return fileDescriptor_d61ab7221f0b5518, []int{38}
return fileDescriptor_d61ab7221f0b5518, []int{37}
}
func (m *SyncSocialLinks) XXX_Unmarshal(b []byte) error {
@ -3396,7 +3298,6 @@ 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")
@ -3437,7 +3338,6 @@ func init() {
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((*SyncSocialLinks)(nil), "protobuf.SyncSocialLinks")
}
@ -3446,225 +3346,216 @@ func init() {
}
var fileDescriptor_d61ab7221f0b5518 = []byte{
// 3517 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x3a, 0x4d, 0x73, 0x23, 0x49,
0x56, 0xa3, 0x0f, 0xeb, 0xe3, 0x49, 0x96, 0xcb, 0x69, 0xcf, 0x58, 0xed, 0xf6, 0x6c, 0x77, 0x57,
0xef, 0xc4, 0x36, 0xc4, 0xe0, 0x01, 0x0f, 0xb0, 0xec, 0xf4, 0x4c, 0x0c, 0x6a, 0x49, 0xd3, 0xed,
0x76, 0x5b, 0x36, 0x69, 0x7b, 0x86, 0x25, 0x88, 0x28, 0xd2, 0x55, 0xd9, 0x56, 0xad, 0x4b, 0x55,
0xa2, 0x32, 0x65, 0xa3, 0x3d, 0x10, 0x40, 0x04, 0x67, 0x22, 0xb8, 0x2c, 0xc7, 0x39, 0x73, 0x24,
0x82, 0x03, 0x11, 0x1c, 0x38, 0x11, 0xfb, 0x1f, 0xe0, 0xca, 0x85, 0xe0, 0xc2, 0x8d, 0x03, 0x07,
0xe2, 0x65, 0x66, 0x95, 0xaa, 0xf4, 0x61, 0xec, 0xe0, 0xc4, 0xc9, 0xf5, 0x5e, 0xbe, 0x7c, 0xf9,
0x32, 0xdf, 0xf7, 0xb3, 0x60, 0x7d, 0xcc, 0xfc, 0xd8, 0x0f, 0xaf, 0xf6, 0xc7, 0x71, 0x24, 0x23,
0x52, 0x53, 0x7f, 0x2e, 0x27, 0xef, 0x77, 0xb7, 0xdc, 0x21, 0x93, 0x8e, 0xef, 0xf1, 0x50, 0xfa,
0x72, 0xaa, 0x97, 0x77, 0xb7, 0xc4, 0x34, 0x74, 0x1d, 0xc1, 0xa5, 0xf4, 0xc3, 0x2b, 0x61, 0x90,
0x36, 0x1b, 0x8f, 0x03, 0xdf, 0x65, 0xd2, 0x8f, 0x42, 0x67, 0xc4, 0x25, 0xf3, 0x98, 0x64, 0xce,
0x88, 0x0b, 0xc1, 0xae, 0xb8, 0xa1, 0xd9, 0x74, 0xa3, 0xd1, 0x68, 0x12, 0xfa, 0xd2, 0xe7, 0x66,
0x9b, 0xcd, 0xe0, 0xf1, 0x37, 0x5c, 0xba, 0x43, 0x3f, 0xbc, 0x7a, 0xc5, 0xdc, 0x6b, 0xee, 0x5d,
0x8c, 0x7b, 0x4c, 0xb2, 0x1e, 0x97, 0xcc, 0x0f, 0x04, 0x79, 0x02, 0x0d, 0xc5, 0x27, 0x9c, 0x8c,
0x2e, 0x79, 0xdc, 0x2e, 0x3c, 0x2d, 0xbc, 0x58, 0xa7, 0x80, 0xa8, 0x81, 0xc2, 0x90, 0x67, 0xd0,
0x94, 0x91, 0x64, 0x41, 0x42, 0x51, 0x54, 0x14, 0x0d, 0x85, 0xd3, 0x24, 0xf6, 0x7f, 0x57, 0xa0,
0x82, 0xbc, 0x27, 0x63, 0xb2, 0x0d, 0x6b, 0x6e, 0x10, 0xb9, 0xd7, 0x8a, 0x51, 0x99, 0x6a, 0x80,
0xb4, 0xa0, 0xe8, 0x7b, 0x6a, 0x67, 0x9d, 0x16, 0x7d, 0x8f, 0x7c, 0x0d, 0x35, 0x37, 0x0a, 0x25,
0x73, 0xa5, 0x68, 0x97, 0x9e, 0x96, 0x5e, 0x34, 0x0e, 0x9e, 0xef, 0x27, 0x2f, 0xb2, 0x7f, 0x36,
0x0d, 0xdd, 0xc3, 0x50, 0x48, 0x16, 0x04, 0xea, 0xae, 0x5d, 0x4d, 0xf9, 0xed, 0x01, 0x4d, 0x37,
0x91, 0x9f, 0x40, 0x23, 0x73, 0xd3, 0x76, 0x59, 0xf1, 0xd8, 0xc9, 0xf3, 0xe8, 0x1a, 0x82, 0x29,
0xcd, 0xd2, 0x92, 0x13, 0xd8, 0x48, 0xd8, 0x98, 0x37, 0x68, 0xaf, 0x3d, 0x2d, 0xbc, 0x68, 0x1c,
0x7c, 0x32, 0xdb, 0x7e, 0xc7, 0x83, 0xd1, 0xf9, 0xdd, 0xe4, 0x02, 0x48, 0x86, 0x7f, 0xc2, 0xb3,
0xf2, 0x10, 0x9e, 0x4b, 0x18, 0x90, 0xcf, 0xa1, 0x3a, 0x8e, 0xa3, 0xf7, 0x7e, 0xc0, 0xdb, 0x55,
0xc5, 0xeb, 0xd1, 0x8c, 0x57, 0xc2, 0xe3, 0x54, 0x13, 0xd0, 0x84, 0x92, 0x1c, 0x43, 0xcb, 0x7c,
0x26, 0x72, 0xd4, 0x1e, 0x22, 0xc7, 0xdc, 0x66, 0xf2, 0x19, 0x54, 0x8d, 0x11, 0xb6, 0xeb, 0x8a,
0xcf, 0x87, 0xf9, 0x27, 0x3e, 0xd3, 0x8b, 0x34, 0xa1, 0xc2, 0xc7, 0x4d, 0xac, 0x36, 0x11, 0x00,
0x1e, 0xf4, 0xb8, 0x73, 0xbb, 0x51, 0x82, 0x6b, 0x3e, 0x45, 0xe7, 0x69, 0x37, 0x96, 0x49, 0x70,
0xa4, 0x17, 0x69, 0x42, 0x85, 0x2f, 0x60, 0x3e, 0x13, 0x01, 0x9a, 0x0f, 0x7a, 0x81, 0xfc, 0x66,
0xd2, 0x01, 0xeb, 0x96, 0x49, 0x77, 0x78, 0x12, 0x06, 0xd3, 0x8e, 0xeb, 0x46, 0x93, 0x50, 0xb6,
0xd7, 0x97, 0x09, 0x62, 0x16, 0xe9, 0x02, 0x39, 0x71, 0x60, 0x67, 0x1e, 0x97, 0x88, 0xd6, 0x7a,
0x88, 0x68, 0xab, 0xb8, 0xd8, 0xff, 0x51, 0x86, 0xe6, 0xf1, 0x24, 0x90, 0x7e, 0x72, 0x22, 0x81,
0x72, 0xc8, 0x46, 0x5c, 0xf9, 0x60, 0x9d, 0xaa, 0x6f, 0xb2, 0x07, 0x75, 0xe9, 0x8f, 0xb8, 0x90,
0x6c, 0x34, 0x56, 0x9e, 0x58, 0xa2, 0x33, 0x04, 0xae, 0xea, 0x10, 0xe4, 0x46, 0x61, 0xbb, 0xa4,
0xb6, 0xcd, 0x10, 0xe4, 0x6b, 0x00, 0x37, 0x0a, 0xa2, 0xd8, 0x19, 0x32, 0x31, 0x34, 0xce, 0xf6,
0x74, 0x26, 0x74, 0xf6, 0xec, 0xfd, 0x2e, 0x12, 0xbe, 0x61, 0x62, 0x48, 0xeb, 0x6e, 0xf2, 0x49,
0x1e, 0xa1, 0xbf, 0x23, 0x03, 0xdf, 0x53, 0xce, 0x56, 0xa2, 0x55, 0x05, 0x1f, 0x7a, 0xe4, 0x47,
0xb0, 0x71, 0xcd, 0xa7, 0x2e, 0x8b, 0x3d, 0xc7, 0x84, 0x48, 0xe5, 0x3a, 0x75, 0xa5, 0x09, 0x44,
0x9f, 0x6a, 0x2c, 0xd9, 0x51, 0x96, 0xe0, 0x4c, 0x7c, 0x4f, 0xf9, 0x43, 0x9d, 0x56, 0xae, 0xf9,
0xf4, 0xc2, 0xf7, 0xc8, 0x97, 0x50, 0xf1, 0x47, 0xec, 0x8a, 0xa3, 0xad, 0xa3, 0x64, 0x3f, 0x5c,
0x21, 0xd9, 0xa1, 0x89, 0xb1, 0x87, 0x48, 0x4c, 0xcd, 0x1e, 0xf2, 0x19, 0x6c, 0xb9, 0x13, 0x21,
0xa3, 0x91, 0xff, 0x73, 0x1d, 0x59, 0x95, 0x60, 0xca, 0xdc, 0xeb, 0x94, 0xe4, 0x96, 0xd4, 0xd5,
0x76, 0x9f, 0x41, 0x3d, 0xbd, 0x23, 0x86, 0x3b, 0x3f, 0xf4, 0xf8, 0x9f, 0xb4, 0x0b, 0x4f, 0x4b,
0x2f, 0x4a, 0x54, 0x03, 0xbb, 0xff, 0x52, 0x80, 0xf5, 0xdc, 0x69, 0x59, 0xe1, 0x0b, 0x39, 0xe1,
0x13, 0x55, 0x15, 0x33, 0xaa, 0x6a, 0x43, 0x75, 0xcc, 0xa6, 0x41, 0xc4, 0x3c, 0xa5, 0x8a, 0x26,
0x4d, 0x40, 0x3c, 0xee, 0xd6, 0xf7, 0x24, 0xea, 0x00, 0x1f, 0x51, 0x03, 0xe4, 0x23, 0xa8, 0x0c,
0xb9, 0x7f, 0x35, 0x94, 0xe6, 0x6d, 0x0d, 0x44, 0x76, 0xa1, 0x86, 0xce, 0x2c, 0xfc, 0x9f, 0x73,
0xf5, 0xa6, 0x25, 0x9a, 0xc2, 0xe4, 0x39, 0xac, 0xc7, 0xea, 0xcb, 0x91, 0x2c, 0xbe, 0xe2, 0x52,
0xbd, 0x69, 0x89, 0x36, 0x35, 0xf2, 0x5c, 0xe1, 0x66, 0xc1, 0xbc, 0x96, 0x09, 0xe6, 0xf6, 0x2f,
0x8a, 0xb0, 0xf5, 0x2e, 0x72, 0x59, 0x60, 0x34, 0x73, 0x6a, 0x84, 0xfb, 0x2d, 0x28, 0x5f, 0xf3,
0xa9, 0x50, 0x4f, 0xd1, 0x38, 0x78, 0x36, 0xd3, 0xc2, 0x12, 0xe2, 0xfd, 0x23, 0x3e, 0xa5, 0x8a,
0x9c, 0x7c, 0x01, 0xcd, 0x11, 0xaa, 0x89, 0x19, 0xef, 0x2a, 0x2a, 0x9f, 0xf8, 0x68, 0xb9, 0x12,
0x69, 0x8e, 0x16, 0x6f, 0x38, 0x66, 0x42, 0xdc, 0x46, 0xb1, 0x67, 0xac, 0x36, 0x85, 0xf1, 0x15,
0x31, 0xb5, 0x1e, 0xf1, 0xa9, 0x7a, 0xad, 0x3a, 0x4d, 0x40, 0xf2, 0x22, 0x35, 0x39, 0x23, 0x94,
0xce, 0x00, 0x75, 0x3a, 0x8f, 0xde, 0xfd, 0x35, 0x28, 0xe1, 0x86, 0x65, 0xfe, 0x44, 0xa0, 0x8c,
0x49, 0x52, 0x89, 0xdb, 0xa4, 0xea, 0xdb, 0xfe, 0x87, 0x02, 0x7c, 0x98, 0xbb, 0x2c, 0xe7, 0xf1,
0x1b, 0x1e, 0x04, 0x11, 0x5a, 0xb9, 0xb1, 0x6e, 0xe7, 0x86, 0xc7, 0xc2, 0x8f, 0x42, 0xc5, 0x6c,
0x8d, 0xb6, 0x0c, 0xfa, 0x5b, 0x8d, 0x45, 0x43, 0x19, 0x73, 0xae, 0x1c, 0x45, 0x73, 0xae, 0x20,
0x78, 0xe8, 0xa9, 0x3c, 0xcd, 0x6f, 0x7c, 0x97, 0x3b, 0x4a, 0x14, 0x7d, 0x5b, 0xd0, 0xa8, 0x01,
0x0a, 0x34, 0x23, 0x90, 0xd3, 0x31, 0x37, 0x77, 0x36, 0x04, 0xe7, 0xd3, 0xb1, 0x8a, 0x00, 0xc2,
0xbf, 0x0a, 0x99, 0x9c, 0xc4, 0x5c, 0x5d, 0xb8, 0x49, 0x67, 0x08, 0xfb, 0xfb, 0x02, 0x58, 0x28,
0x76, 0x36, 0xf3, 0xae, 0xc8, 0xe6, 0x3f, 0x82, 0x0d, 0x3f, 0x43, 0xe5, 0xa4, 0xa9, 0xbd, 0x95,
0x45, 0xe7, 0x64, 0x56, 0x22, 0x95, 0x16, 0x44, 0x4a, 0x1e, 0xb6, 0x9c, 0xb7, 0xfe, 0xe4, 0x89,
0xd6, 0x54, 0xa9, 0x91, 0x80, 0xf6, 0xbf, 0x17, 0x60, 0x67, 0x45, 0x71, 0x70, 0xcf, 0xba, 0xe3,
0x39, 0xac, 0x9b, 0x0c, 0xe7, 0x28, 0xf7, 0x37, 0x22, 0x35, 0x0d, 0x52, 0xfb, 0xea, 0x23, 0xa8,
0xf1, 0x50, 0x38, 0x19, 0xc1, 0xaa, 0x3c, 0x14, 0xea, 0x8d, 0x9f, 0x41, 0x33, 0x60, 0x42, 0x3a,
0x93, 0xb1, 0xc7, 0x24, 0xd7, 0xb1, 0xac, 0x4c, 0x1b, 0x88, 0xbb, 0xd0, 0x28, 0xbc, 0xb3, 0x98,
0x0a, 0xc9, 0x47, 0x8e, 0x64, 0x57, 0x58, 0x06, 0x94, 0xf0, 0xce, 0x1a, 0x75, 0xce, 0xae, 0x04,
0xf9, 0x04, 0x5a, 0x01, 0xda, 0x88, 0x13, 0xfa, 0xee, 0xb5, 0x3a, 0x44, 0x87, 0xb3, 0x75, 0x85,
0x1d, 0x18, 0xa4, 0xfd, 0xe7, 0x15, 0x78, 0xb4, 0xb2, 0x12, 0x22, 0xbf, 0x0e, 0xdb, 0x59, 0x41,
0x1c, 0xb5, 0x37, 0x98, 0x9a, 0xdb, 0x93, 0x8c, 0x40, 0xef, 0xf4, 0xca, 0xff, 0xe3, 0xa7, 0x40,
0xdd, 0x32, 0xcf, 0xe3, 0x9e, 0x0a, 0xca, 0x35, 0xaa, 0x01, 0xb4, 0x93, 0x4b, 0x54, 0x32, 0xf7,
0x54, 0x89, 0x51, 0xa3, 0x09, 0x88, 0xf4, 0xa3, 0x09, 0xca, 0xd4, 0xd0, 0xf4, 0x0a, 0x40, 0xfa,
0x98, 0x8f, 0xa2, 0x1b, 0xee, 0xa9, 0x8a, 0xa0, 0x46, 0x13, 0x90, 0x3c, 0x85, 0xe6, 0x90, 0x09,
0x47, 0xb1, 0x75, 0x26, 0x42, 0xe5, 0xf7, 0x1a, 0x85, 0x21, 0x13, 0x1d, 0x44, 0x5d, 0xa8, 0x24,
0x71, 0xc3, 0x63, 0xff, 0x7d, 0x52, 0x7d, 0x0b, 0xc9, 0xe4, 0x44, 0xa7, 0xef, 0x12, 0x25, 0xd9,
0xa5, 0x33, 0xb5, 0xa2, 0x8a, 0xe6, 0x78, 0x22, 0x64, 0x42, 0xb9, 0xa1, 0x28, 0x1b, 0x0a, 0x67,
0x48, 0xbe, 0x82, 0xc7, 0xa6, 0x92, 0x74, 0x62, 0xfe, 0xc7, 0x13, 0x2e, 0xa4, 0xd6, 0xa2, 0xda,
0xc2, 0xdb, 0x96, 0xda, 0xd1, 0x36, 0x24, 0x54, 0x53, 0x28, 0x65, 0xe2, 0x7e, 0xbe, 0x7a, 0xbb,
0x76, 0x83, 0xcd, 0x95, 0xdb, 0xbb, 0xca, 0x33, 0xbe, 0x86, 0xbd, 0xf9, 0xed, 0xf8, 0x1c, 0x92,
0x9b, 0xe3, 0x89, 0xda, 0xff, 0x28, 0xbf, 0x9f, 0x2a, 0x0a, 0x7d, 0xfe, 0x6a, 0x06, 0x5a, 0x80,
0xad, 0xd5, 0x0c, 0xb4, 0x04, 0xcf, 0xa0, 0xe9, 0xf9, 0x62, 0x1c, 0xb0, 0xa9, 0xb6, 0xaf, 0x6d,
0xa5, 0xfa, 0x86, 0xc1, 0xa1, 0x8d, 0xd9, 0xb7, 0x8b, 0xfe, 0x9e, 0x94, 0x38, 0xcb, 0xfd, 0x7d,
0xc1, 0xa8, 0x8b, 0x4b, 0x8c, 0x7a, 0xde, 0x72, 0x4b, 0x0b, 0x96, 0x6b, 0xbf, 0x82, 0xdd, 0xf9,
0x83, 0x4f, 0x27, 0x97, 0x81, 0xef, 0x76, 0x87, 0xec, 0x9e, 0xb1, 0xc6, 0xfe, 0xfb, 0x12, 0xac,
0xe7, 0xda, 0x90, 0xff, 0x75, 0x5f, 0x53, 0x39, 0xe6, 0x13, 0x68, 0x8c, 0x63, 0xff, 0x86, 0x49,
0xee, 0x5c, 0xf3, 0xa9, 0xa9, 0x00, 0xc0, 0xa0, 0x30, 0x1b, 0x3d, 0xc5, 0xa8, 0x2a, 0xdc, 0xd8,
0x1f, 0xa3, 0x5c, 0xca, 0x2f, 0x9b, 0x34, 0x8b, 0xc2, 0x82, 0xe0, 0x67, 0x91, 0x1f, 0x1a, 0xaf,
0xac, 0x51, 0x03, 0x61, 0xba, 0xd4, 0xb6, 0xca, 0x3d, 0x55, 0x10, 0xd4, 0x68, 0x0a, 0xcf, 0x9c,
0xa6, 0x9a, 0x75, 0x9a, 0x13, 0xb0, 0x8c, 0x76, 0x85, 0x23, 0x23, 0x07, 0xf9, 0x98, 0x2a, 0xeb,
0x93, 0x55, 0xcd, 0x96, 0x21, 0x3f, 0x8f, 0xde, 0x46, 0x7e, 0x48, 0x5b, 0x71, 0x0e, 0x26, 0x2f,
0xa1, 0x96, 0x94, 0xf8, 0xa6, 0xa5, 0x78, 0xb2, 0x82, 0x91, 0xe9, 0x2d, 0x04, 0x4d, 0x37, 0x60,
0x06, 0xe3, 0xa1, 0x1b, 0x4f, 0xc7, 0x32, 0x75, 0xfa, 0x19, 0x42, 0xe5, 0xb7, 0x31, 0x77, 0x25,
0x9b, 0xb9, 0xfe, 0x0c, 0x81, 0x49, 0xcb, 0x90, 0xa2, 0x03, 0xab, 0x42, 0xa5, 0xa9, 0x5e, 0xae,
0x35, 0x43, 0x1f, 0xf1, 0xa9, 0xc0, 0xf2, 0xe6, 0xf1, 0x1d, 0x37, 0x32, 0xfa, 0x2a, 0xa4, 0xfa,
0xfa, 0x18, 0x60, 0xac, 0x6c, 0x43, 0xa9, 0x4b, 0xeb, 0xbf, 0xae, 0x31, 0xa8, 0xad, 0x54, 0xe9,
0xa5, 0xac, 0xd2, 0xef, 0x08, 0xac, 0x3b, 0xba, 0x6e, 0x49, 0x4a, 0xe5, 0x3a, 0xad, 0x20, 0x78,
0xe8, 0xa1, 0xdd, 0x26, 0x6d, 0xe2, 0x14, 0x57, 0x2b, 0x5a, 0xf1, 0x29, 0xee, 0x50, 0x29, 0x51,
0xbb, 0x6f, 0x55, 0x1f, 0xa6, 0x00, 0xf2, 0x0d, 0x6c, 0xc6, 0xfc, 0x86, 0xb3, 0x80, 0x7b, 0x8e,
0xa9, 0x9c, 0x92, 0x5a, 0x39, 0xd3, 0x53, 0x52, 0x43, 0x92, 0x36, 0x32, 0x71, 0x1e, 0x21, 0xec,
0xbf, 0x2e, 0x82, 0x35, 0xef, 0x16, 0xe4, 0xab, 0x4c, 0x2b, 0xbf, 0x50, 0xf9, 0xad, 0x48, 0x60,
0x99, 0x46, 0xfe, 0x35, 0x34, 0xcd, 0xeb, 0xe1, 0x2d, 0x45, 0xbb, 0x38, 0x5f, 0xc2, 0xaf, 0xf6,
0x43, 0xda, 0x18, 0xa7, 0xdf, 0x82, 0xbc, 0x84, 0x6a, 0x52, 0x41, 0x96, 0x94, 0x5d, 0xdd, 0x21,
0x46, 0x72, 0xc5, 0x64, 0xc7, 0xff, 0x61, 0x9c, 0x60, 0xff, 0x18, 0x36, 0xd4, 0x2a, 0x0a, 0x64,
0xf2, 0xc9, 0xfd, 0xe2, 0xc3, 0x97, 0xb0, 0x9d, 0x6c, 0x3c, 0xd6, 0x33, 0x1c, 0x41, 0x39, 0xbb,
0xef, 0xee, 0xdf, 0x85, 0x8f, 0x74, 0xd7, 0x29, 0xfd, 0x1b, 0x5f, 0x4e, 0xbb, 0x3c, 0x94, 0x3c,
0xbe, 0x63, 0xbf, 0x05, 0x25, 0xdf, 0xd3, 0xcf, 0xdb, 0xa4, 0xf8, 0x69, 0xf7, 0x74, 0x8c, 0xcb,
0x73, 0xe8, 0xb8, 0x2e, 0x57, 0xce, 0x74, 0x5f, 0x2e, 0x7d, 0xed, 0x2c, 0x79, 0x2e, 0x3d, 0x5f,
0x8c, 0x7c, 0x21, 0x1e, 0xc0, 0xc6, 0x81, 0xe7, 0x8b, 0x6c, 0x06, 0x91, 0xcc, 0xe5, 0x55, 0x8e,
0xbe, 0x96, 0x54, 0x3c, 0x4c, 0x1a, 0x9e, 0x75, 0x83, 0xe9, 0x48, 0xf4, 0x2a, 0x4c, 0xe4, 0x82,
0xf3, 0x50, 0x3d, 0x55, 0x8d, 0x56, 0x87, 0x4c, 0x9c, 0x71, 0x1e, 0xda, 0x7f, 0x55, 0x80, 0x27,
0x77, 0x9f, 0x20, 0x48, 0x00, 0x1f, 0x33, 0xb3, 0xec, 0xb8, 0x6a, 0xdd, 0x09, 0xb3, 0x04, 0xc6,
0xbe, 0x5f, 0xcc, 0x37, 0xfe, 0xab, 0x38, 0xd2, 0xc7, 0x6c, 0xf5, 0x69, 0xf6, 0x3f, 0xd6, 0xe1,
0x07, 0x77, 0xef, 0x5f, 0x08, 0x35, 0x0b, 0x3d, 0x7c, 0x39, 0xdb, 0xc3, 0xbf, 0x87, 0xcd, 0xac,
0xb8, 0xb3, 0x9a, 0xbb, 0x75, 0xf0, 0x93, 0xfb, 0x8a, 0xbc, 0x9f, 0x05, 0xb0, 0x44, 0xa7, 0x56,
0x38, 0x87, 0xc9, 0x06, 0xa8, 0x72, 0x2e, 0x40, 0x11, 0x28, 0xc7, 0x9c, 0x25, 0x49, 0x47, 0x7d,
0xa3, 0xc8, 0x5e, 0x62, 0x0d, 0x26, 0xe7, 0xcc, 0x10, 0x98, 0x90, 0x98, 0xb1, 0x38, 0x93, 0x77,
0x52, 0x18, 0xeb, 0x35, 0x33, 0xdb, 0x54, 0xed, 0x67, 0x93, 0x26, 0x20, 0xa6, 0x37, 0x36, 0x91,
0xc3, 0xb4, 0x4b, 0x37, 0x90, 0xee, 0x69, 0xc7, 0xc1, 0x34, 0x99, 0x89, 0xaa, 0x14, 0xd1, 0xc4,
0x9e, 0x76, 0x1c, 0x4c, 0x8d, 0x8f, 0x2d, 0x44, 0xd1, 0x86, 0x2e, 0x3b, 0xb2, 0x51, 0xf4, 0x3d,
0x6c, 0x8e, 0xf8, 0xe8, 0x92, 0xc7, 0x62, 0xe8, 0x8f, 0x93, 0x0a, 0xae, 0xf9, 0xc0, 0x87, 0x3c,
0x4e, 0x39, 0xe8, 0x7a, 0x8f, 0x5a, 0xa3, 0x39, 0x0c, 0xf9, 0x8b, 0xc2, 0xac, 0x86, 0x5b, 0x56,
0x5e, 0xae, 0xab, 0x23, 0x5f, 0xdd, 0xfb, 0xc8, 0xa4, 0x3d, 0x58, 0x28, 0x47, 0xd3, 0x32, 0x6c,
0x71, 0x09, 0x9f, 0xd9, 0xe3, 0x01, 0x47, 0x0d, 0xb4, 0xb4, 0xcb, 0x18, 0x70, 0xce, 0xd9, 0x36,
0xe6, 0x9c, 0xcd, 0xfe, 0xcf, 0x02, 0x58, 0xf3, 0xd6, 0x42, 0x00, 0x2a, 0x83, 0x08, 0xbf, 0xac,
0x0f, 0xc8, 0x06, 0x34, 0x06, 0xfc, 0xf6, 0x24, 0xe4, 0xe7, 0xd1, 0x49, 0xc8, 0xad, 0x02, 0xd9,
0x81, 0xad, 0x01, 0xbf, 0x3d, 0xd5, 0x95, 0xcc, 0xeb, 0x38, 0x9a, 0x8c, 0x31, 0xf8, 0x59, 0x45,
0xd2, 0x80, 0xea, 0x31, 0x0f, 0x91, 0x89, 0x55, 0x22, 0x75, 0x58, 0xa3, 0xa8, 0x30, 0xab, 0x4c,
0x08, 0xb4, 0xba, 0xb9, 0xfa, 0xd1, 0x5a, 0x43, 0x26, 0x69, 0x24, 0x3e, 0x0c, 0x6f, 0x7c, 0xa9,
0x0e, 0xb7, 0x2a, 0x64, 0x1b, 0xac, 0xf9, 0x94, 0x6d, 0x55, 0xc9, 0x0f, 0x60, 0x37, 0xc5, 0xce,
0x54, 0x92, 0xac, 0xd7, 0xc8, 0x16, 0x6c, 0xa4, 0xeb, 0x47, 0x3e, 0xb6, 0x0f, 0x56, 0x5d, 0x9f,
0xb1, 0xf0, 0x60, 0x16, 0xd8, 0x7f, 0x59, 0x00, 0x6b, 0x5e, 0xb1, 0xa4, 0x0d, 0xdb, 0xf3, 0xb8,
0x43, 0x2f, 0xc0, 0x17, 0x78, 0x0c, 0x3b, 0xf3, 0x2b, 0xa7, 0x3c, 0xf4, 0xfc, 0xf0, 0xca, 0x2a,
0x90, 0x3d, 0x68, 0xcf, 0x2f, 0x26, 0xd1, 0xd7, 0x2a, 0x2e, 0x5b, 0xed, 0x71, 0x37, 0xc0, 0x32,
0xce, 0x2a, 0xd9, 0x7f, 0x56, 0x80, 0x47, 0x2b, 0xb5, 0x8d, 0xcf, 0x79, 0x11, 0x5e, 0x87, 0xd1,
0x6d, 0x68, 0x7d, 0x80, 0xc0, 0xec, 0xcc, 0x26, 0xd4, 0x32, 0x67, 0x34, 0xa1, 0x36, 0xe3, 0x49,
0xd6, 0xa1, 0xde, 0x65, 0xa1, 0xcb, 0x83, 0x80, 0x7b, 0x56, 0x19, 0xf7, 0x9d, 0x63, 0xb7, 0xc2,
0x3d, 0x6b, 0x8d, 0x6c, 0xc2, 0xfa, 0x45, 0xa8, 0xc0, 0xef, 0xa2, 0x58, 0x0e, 0xa7, 0x56, 0xc5,
0xfe, 0xbe, 0x00, 0x4d, 0xb4, 0xc7, 0x57, 0x51, 0x74, 0x3d, 0x62, 0xf1, 0xf5, 0xea, 0x50, 0x3f,
0x89, 0x03, 0x93, 0xb8, 0xf0, 0x33, 0xed, 0xf9, 0x4b, 0x99, 0x9e, 0xff, 0x31, 0xd4, 0x55, 0xbd,
0xee, 0x20, 0xad, 0x0e, 0x2a, 0x35, 0x85, 0xb8, 0x88, 0x83, 0x6c, 0xe3, 0xb6, 0x96, 0x6f, 0xdc,
0x3e, 0x06, 0x30, 0xc6, 0x8a, 0x16, 0x5a, 0xd1, 0x16, 0x6a, 0x30, 0x1d, 0x69, 0xff, 0x29, 0x7c,
0x88, 0x12, 0xf6, 0x43, 0x71, 0x21, 0x78, 0x8c, 0x07, 0xe9, 0x89, 0xe9, 0x0a, 0x51, 0x77, 0xa1,
0x36, 0x31, 0x74, 0x46, 0xde, 0x14, 0x56, 0x03, 0xcc, 0x21, 0xf3, 0xd5, 0xac, 0x43, 0x17, 0x72,
0x55, 0x05, 0x1f, 0xe6, 0xfa, 0xca, 0x72, 0x4e, 0x3c, 0xfb, 0xad, 0x2e, 0x97, 0xba, 0x01, 0x67,
0xf1, 0x1b, 0x5f, 0xc8, 0x28, 0x9e, 0x66, 0x83, 0x67, 0x21, 0x17, 0x3c, 0x3f, 0x06, 0x70, 0x91,
0x50, 0xdf, 0xc5, 0x04, 0x77, 0x83, 0xe9, 0x48, 0xfb, 0x97, 0x05, 0x20, 0xc8, 0xcc, 0x4c, 0xfc,
0x4f, 0x7d, 0x57, 0x4e, 0x62, 0xbe, 0x74, 0x32, 0x95, 0x19, 0x1f, 0x16, 0x57, 0x8c, 0x0f, 0x4b,
0x6a, 0xb0, 0xb2, 0x30, 0x3e, 0x2c, 0x2b, 0x74, 0x32, 0x3e, 0x7c, 0x0c, 0x75, 0xd5, 0x49, 0xa9,
0xf9, 0xa1, 0x1e, 0xc5, 0xa8, 0xf9, 0xe1, 0xd9, 0xd2, 0xf9, 0x61, 0x45, 0x11, 0xac, 0x98, 0x1f,
0x56, 0xb3, 0xf3, 0xc3, 0x21, 0x6c, 0x2d, 0xde, 0x44, 0xac, 0x1e, 0x91, 0xfe, 0x0e, 0xd4, 0xc6,
0x86, 0xc8, 0x94, 0x87, 0x7b, 0xf9, 0x90, 0x98, 0xe7, 0x44, 0x53, 0x6a, 0xfb, 0x97, 0x45, 0x68,
0x64, 0x66, 0xf3, 0x2b, 0xf4, 0xde, 0x86, 0x2a, 0xf3, 0xbc, 0x98, 0x0b, 0x91, 0xbc, 0x97, 0x01,
0xb3, 0x22, 0x95, 0x72, 0x22, 0xe5, 0x6b, 0x7e, 0xdd, 0x81, 0x65, 0x6a, 0x7e, 0x02, 0xe5, 0x31,
0x93, 0x43, 0x53, 0xbf, 0xab, 0xef, 0x54, 0x53, 0x95, 0x8c, 0xa6, 0xb2, 0x63, 0xf1, 0xaa, 0x99,
0x51, 0x9a, 0xb1, 0xf8, 0x36, 0xac, 0xf1, 0x51, 0xf4, 0x33, 0x5f, 0xe5, 0xbe, 0x3a, 0xd5, 0x00,
0xaa, 0xea, 0x96, 0x05, 0x01, 0x97, 0x66, 0x14, 0x62, 0x20, 0x64, 0x8e, 0x66, 0x64, 0x7a, 0x22,
0xf5, 0xad, 0xd4, 0xea, 0x7b, 0x1e, 0x0f, 0x4d, 0x2f, 0x64, 0xa0, 0x3b, 0xe6, 0x20, 0xbb, 0x50,
0x1b, 0x47, 0xc2, 0x57, 0x5d, 0xe5, 0xba, 0x9e, 0x17, 0x27, 0xb0, 0xfd, 0x6f, 0xe6, 0x29, 0xcd,
0xff, 0x5b, 0x56, 0x3c, 0x65, 0xe6, 0xc1, 0x8a, 0x4b, 0xc7, 0xdc, 0xa5, 0xfc, 0x04, 0x35, 0x33,
0xa9, 0x54, 0xdf, 0x6a, 0x28, 0xc0, 0x63, 0xff, 0x86, 0x7b, 0xce, 0xfb, 0x38, 0x1a, 0x99, 0x17,
0x6c, 0x18, 0xdc, 0x37, 0x71, 0x34, 0x22, 0x2f, 0x61, 0x57, 0xb7, 0xef, 0x82, 0x7b, 0x8e, 0x5a,
0x30, 0x53, 0x48, 0x35, 0x87, 0xd7, 0x41, 0x60, 0x47, 0x35, 0xf3, 0x82, 0x7b, 0xbd, 0x74, 0xfd,
0x10, 0x97, 0xf5, 0x48, 0x2a, 0x74, 0x13, 0xf6, 0xfa, 0xd1, 0x41, 0xa3, 0x14, 0xf7, 0xdf, 0x50,
0x15, 0x49, 0xb6, 0x45, 0x5a, 0xf1, 0x7f, 0x9e, 0x94, 0x0c, 0xb7, 0x98, 0xb9, 0x31, 0xb6, 0xb4,
0xa5, 0xa5, 0xff, 0xa3, 0xc2, 0x55, 0x9a, 0x92, 0x65, 0x75, 0x00, 0xf9, 0x98, 0xf1, 0x5f, 0x05,
0x1d, 0x34, 0xce, 0xd8, 0x0d, 0xf7, 0x3a, 0xc6, 0x0e, 0x33, 0x16, 0x5a, 0xc8, 0x5b, 0xe8, 0xb2,
0x7f, 0x1f, 0xec, 0x41, 0xfd, 0x3d, 0xbb, 0x89, 0x26, 0xb1, 0x2f, 0xf5, 0x83, 0xd7, 0xe8, 0x0c,
0x71, 0x47, 0x34, 0x7d, 0x06, 0x4d, 0x9d, 0xdd, 0x9d, 0xac, 0xd3, 0x36, 0x34, 0x4e, 0xcf, 0x6c,
0x7e, 0x15, 0x36, 0x75, 0x18, 0x14, 0xc3, 0x28, 0x96, 0xaa, 0x7d, 0x15, 0xc6, 0x42, 0x37, 0xd4,
0xc2, 0x19, 0xe2, 0xb1, 0x8d, 0x15, 0x18, 0xf9, 0x79, 0x28, 0x4c, 0x89, 0x86, 0x9f, 0x68, 0x1d,
0xbe, 0x70, 0x24, 0x17, 0x89, 0xa1, 0x56, 0x7c, 0x71, 0xce, 0x85, 0x7c, 0x5b, 0xae, 0x95, 0xad,
0x35, 0xfb, 0x17, 0x05, 0x1d, 0xaf, 0x17, 0x26, 0x00, 0x2b, 0x8c, 0x6d, 0xbe, 0x92, 0x2b, 0x2e,
0x56, 0x72, 0x7d, 0x78, 0x32, 0xd4, 0x81, 0xd7, 0x61, 0xb1, 0x3b, 0xf4, 0x6f, 0xb8, 0x23, 0x26,
0xe3, 0x31, 0xca, 0xce, 0x43, 0x76, 0x19, 0x98, 0xe9, 0x4f, 0x8d, 0xee, 0x19, 0xb2, 0x8e, 0xa6,
0x3a, 0xd3, 0x44, 0x7d, 0x4d, 0x63, 0xff, 0x5d, 0x41, 0x37, 0x79, 0x26, 0x21, 0x62, 0x36, 0xb9,
0xe7, 0xc0, 0xf9, 0x2b, 0xa8, 0x98, 0x62, 0x4e, 0x17, 0xe2, 0x73, 0x53, 0x93, 0x0c, 0xc3, 0xfd,
0xf3, 0xd9, 0x6c, 0x90, 0x9a, 0x4d, 0xf6, 0x17, 0xd0, 0xc8, 0xa0, 0x55, 0x62, 0x1f, 0x1c, 0x0d,
0x4e, 0xbe, 0x1b, 0xe8, 0xc4, 0x7e, 0x4e, 0x2f, 0xce, 0xce, 0xfb, 0x3d, 0xab, 0xa0, 0x12, 0xf4,
0x40, 0x81, 0xdf, 0x9d, 0xd0, 0xf3, 0x37, 0x3f, 0xb5, 0x8a, 0xf6, 0xf7, 0x25, 0x3d, 0x3d, 0xcb,
0x16, 0x08, 0xa6, 0xee, 0x59, 0x21, 0x3c, 0x81, 0xb2, 0xf2, 0x0a, 0x63, 0x4c, 0xf8, 0x8d, 0x17,
0x92, 0x91, 0x71, 0xdb, 0xa2, 0x8c, 0xd0, 0xb8, 0xdc, 0x21, 0x06, 0x9d, 0xf0, 0x2a, 0xf1, 0xdc,
0x19, 0x02, 0x55, 0x62, 0xe6, 0x3d, 0x3a, 0x8d, 0x99, 0xa1, 0x70, 0x8a, 0xeb, 0xa8, 0x7f, 0xd9,
0xc4, 0x5c, 0x8c, 0xa3, 0x50, 0x24, 0xb1, 0x30, 0x85, 0x31, 0xac, 0x62, 0xad, 0xee, 0xeb, 0xcd,
0xda, 0xfe, 0xea, 0x06, 0xd3, 0x91, 0x84, 0x2f, 0x9f, 0xc2, 0xd6, 0xd4, 0xcb, 0xfe, 0x66, 0xfe,
0x65, 0x97, 0xdc, 0x7a, 0x7f, 0x49, 0x61, 0xbc, 0x6c, 0x76, 0xab, 0x75, 0x58, 0x4f, 0x5b, 0xed,
0xdf, 0x07, 0xb2, 0xa2, 0xc8, 0xca, 0xea, 0xe2, 0xb4, 0x3f, 0xe8, 0x1d, 0x0e, 0x5e, 0x9b, 0x22,
0xab, 0xdb, 0xed, 0x9f, 0xa2, 0x66, 0x74, 0x91, 0xd5, 0xef, 0xbe, 0x3b, 0x1c, 0xf4, 0x7b, 0x56,
0x09, 0xa1, 0x6e, 0x67, 0xd0, 0xed, 0xbf, 0xeb, 0xf7, 0xac, 0xb2, 0xfd, 0xaf, 0x05, 0xdd, 0x83,
0xe7, 0x8b, 0xdc, 0x1e, 0x77, 0x7d, 0xb1, 0xfa, 0xbf, 0x2f, 0x7b, 0x50, 0x37, 0xef, 0x79, 0x98,
0x58, 0xda, 0x0c, 0x41, 0xfe, 0x10, 0x36, 0x3c, 0xb3, 0xdf, 0xc9, 0x59, 0xde, 0xe7, 0xf3, 0xd3,
0x8c, 0x65, 0x47, 0xee, 0x27, 0x1f, 0xe6, 0x79, 0x5a, 0x5e, 0x0e, 0xb6, 0x3f, 0x85, 0x56, 0x9e,
0x22, 0x77, 0xd9, 0x0f, 0x72, 0x97, 0x2d, 0xd8, 0xff, 0x5c, 0x84, 0x8d, 0xb9, 0x5f, 0x2a, 0xac,
0xce, 0xf2, 0xf3, 0xe3, 0xe0, 0xe2, 0xc2, 0x38, 0x98, 0x7c, 0x0a, 0x24, 0x4b, 0xe2, 0x64, 0xe7,
0x6a, 0x56, 0x86, 0x50, 0xc7, 0xaa, 0x6c, 0xd9, 0x50, 0x7e, 0x48, 0xd9, 0x40, 0xbe, 0x84, 0xa6,
0x88, 0x5c, 0x9f, 0x05, 0x4e, 0xe0, 0x87, 0xd7, 0xc9, 0xcf, 0x43, 0x1e, 0xcd, 0xfd, 0xf4, 0x41,
0x51, 0xbc, 0x43, 0x02, 0xda, 0x10, 0x33, 0x80, 0xfc, 0x1e, 0x6c, 0xf3, 0x50, 0x38, 0x49, 0xe9,
0xe8, 0x78, 0xe9, 0x0f, 0x42, 0x4a, 0x8b, 0xd3, 0xce, 0x85, 0xda, 0x94, 0x12, 0x3e, 0x8f, 0x12,
0xb6, 0x00, 0xa0, 0xec, 0x36, 0xe9, 0x60, 0x33, 0xf5, 0x5d, 0x21, 0x5f, 0xdf, 0x1d, 0x41, 0xc3,
0xb4, 0xbe, 0xd8, 0x82, 0xa9, 0x27, 0x6c, 0x1d, 0xfc, 0xca, 0xec, 0xc4, 0xce, 0xec, 0x07, 0x44,
0xc7, 0xe6, 0xf7, 0x43, 0x86, 0xe9, 0xbe, 0xea, 0xf5, 0xb3, 0xbb, 0xed, 0xbf, 0x2d, 0x40, 0x0b,
0x45, 0xcc, 0x9c, 0xfc, 0xdb, 0xd0, 0x88, 0x53, 0x28, 0x19, 0x87, 0x6c, 0x67, 0x46, 0x88, 0xe9,
0x22, 0xcd, 0x12, 0x92, 0x03, 0xd8, 0x16, 0x93, 0xcb, 0x64, 0x8e, 0xf8, 0x56, 0x44, 0xe1, 0xab,
0xa9, 0xe4, 0x49, 0xb9, 0xb5, 0x74, 0x8d, 0x7c, 0x0a, 0x9b, 0xc9, 0xdc, 0x77, 0xb6, 0x41, 0x0f,
0xc3, 0x17, 0x17, 0xec, 0xbf, 0x29, 0xa4, 0xe5, 0x09, 0x66, 0x58, 0xd5, 0x76, 0xa4, 0x26, 0x86,
0x9f, 0x4b, 0x33, 0xe5, 0x47, 0x50, 0x31, 0xff, 0x41, 0xd2, 0x59, 0xc0, 0x40, 0x59, 0x23, 0x2d,
0xe7, 0x8c, 0x74, 0x0f, 0xea, 0x26, 0xf3, 0x72, 0x34, 0x8b, 0x12, 0x96, 0x7d, 0x29, 0x62, 0xe6,
0xaf, 0x95, 0x6c, 0xb9, 0xfb, 0x4f, 0x45, 0xd8, 0xcc, 0x88, 0x86, 0xfd, 0x7b, 0x14, 0x92, 0x2f,
0xa0, 0xc2, 0xd4, 0x97, 0x92, 0xb1, 0x75, 0x60, 0x2f, 0x2d, 0x19, 0x34, 0xf1, 0xbe, 0xfe, 0x43,
0xcd, 0x0e, 0xf2, 0x43, 0x58, 0x8f, 0x02, 0xcf, 0x90, 0x5c, 0xa4, 0xf9, 0x26, 0x8f, 0x34, 0xbf,
0x9c, 0x41, 0xc8, 0x0c, 0x44, 0x57, 0x54, 0x25, 0x09, 0x15, 0xe6, 0xdf, 0x8a, 0x91, 0x6e, 0x13,
0xd6, 0x8f, 0xfa, 0x3f, 0xed, 0x76, 0x68, 0xcf, 0xe9, 0xf4, 0x7a, 0xca, 0xb5, 0x09, 0xb4, 0x3a,
0xdd, 0xee, 0xc9, 0xc5, 0xe0, 0xfc, 0xcc, 0xe0, 0x0a, 0xd8, 0x3c, 0x27, 0x64, 0xbd, 0xfe, 0xbb,
0xbe, 0x0e, 0x78, 0xdb, 0x60, 0xa5, 0x84, 0xb4, 0x7f, 0x7c, 0xf2, 0xad, 0x0a, 0x7c, 0x00, 0x95,
0x77, 0x27, 0xdd, 0x23, 0x0c, 0x7b, 0x18, 0x25, 0x2e, 0x06, 0x06, 0x5a, 0x23, 0x1b, 0xd0, 0xb8,
0x38, 0xec, 0x39, 0x17, 0xa7, 0xbd, 0x0e, 0x32, 0xa8, 0x10, 0x0b, 0x9a, 0x83, 0xce, 0x71, 0xdf,
0xe9, 0xbe, 0xe9, 0x0c, 0x5e, 0xf7, 0x7b, 0x56, 0xd5, 0xfe, 0x23, 0x9d, 0x7e, 0x33, 0x2e, 0x47,
0x7e, 0x3c, 0xe7, 0xa3, 0x0b, 0xb6, 0x38, 0x23, 0xce, 0xbb, 0x67, 0xaa, 0xa4, 0x62, 0x46, 0x49,
0xaf, 0xd6, 0xff, 0xa0, 0xb1, 0xff, 0xd9, 0xcb, 0x64, 0xf3, 0x65, 0x45, 0x7d, 0x7d, 0xfe, 0x3f,
0x01, 0x00, 0x00, 0xff, 0xff, 0x9a, 0xb1, 0xaf, 0x0c, 0xb6, 0x27, 0x00, 0x00,
// 3368 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x3a, 0x3d, 0x6f, 0x24, 0x47,
0x76, 0x9a, 0x0f, 0xce, 0xc7, 0x9b, 0x21, 0xd9, 0x2c, 0x52, 0xcb, 0x59, 0x2e, 0x57, 0xbb, 0xdb,
0x6b, 0x41, 0x6b, 0x43, 0xa6, 0xec, 0x95, 0x6d, 0x59, 0x5a, 0x09, 0x32, 0x97, 0xa4, 0xb4, 0xdc,
0x0f, 0x2e, 0x5d, 0x24, 0x25, 0xdb, 0x30, 0xd0, 0x2e, 0x76, 0xd7, 0x72, 0x4a, 0xec, 0xe9, 0x6e,
0x77, 0xd5, 0x90, 0x1e, 0x05, 0x86, 0x6d, 0xc0, 0xb1, 0x01, 0x27, 0xca, 0x0c, 0xc5, 0x0e, 0x0d,
0x38, 0x38, 0xe0, 0xe2, 0x83, 0xfe, 0xc3, 0x5d, 0x7a, 0xc9, 0xe1, 0x92, 0xcb, 0x2e, 0xb8, 0xe0,
0x50, 0xaf, 0xaa, 0x7b, 0xba, 0xe7, 0x83, 0x47, 0xe2, 0xa2, 0x8b, 0xd8, 0xef, 0xd5, 0xab, 0x57,
0xaf, 0x5e, 0xbd, 0xef, 0x21, 0x2c, 0x26, 0x4c, 0xa4, 0x22, 0x3a, 0xdb, 0x4a, 0xd2, 0x58, 0xc5,
0xa4, 0x85, 0x7f, 0x4e, 0x87, 0x6f, 0x36, 0x56, 0xfd, 0x3e, 0x53, 0x9e, 0x08, 0x78, 0xa4, 0x84,
0x1a, 0x99, 0xe5, 0x8d, 0x55, 0x39, 0x8a, 0x7c, 0x4f, 0x72, 0xa5, 0x44, 0x74, 0x26, 0x2d, 0xd2,
0x65, 0x49, 0x12, 0x0a, 0x9f, 0x29, 0x11, 0x47, 0xde, 0x80, 0x2b, 0x16, 0x30, 0xc5, 0xbc, 0x01,
0x97, 0x92, 0x9d, 0x71, 0x4b, 0xb3, 0xe2, 0xc7, 0x83, 0xc1, 0x30, 0x12, 0x4a, 0x70, 0xbb, 0xcd,
0x65, 0x70, 0xe7, 0x0b, 0xae, 0xfc, 0xbe, 0x88, 0xce, 0x9e, 0x32, 0xff, 0x9c, 0x07, 0x27, 0xc9,
0x2e, 0x53, 0x6c, 0x97, 0x2b, 0x26, 0x42, 0x49, 0xee, 0x41, 0x07, 0xf9, 0x44, 0xc3, 0xc1, 0x29,
0x4f, 0x7b, 0x95, 0xfb, 0x95, 0x47, 0x8b, 0x14, 0x34, 0xea, 0x00, 0x31, 0xe4, 0x01, 0x74, 0x55,
0xac, 0x58, 0x98, 0x51, 0x54, 0x91, 0xa2, 0x83, 0x38, 0x43, 0xe2, 0xfe, 0xa6, 0x01, 0x0d, 0xcd,
0x7b, 0x98, 0x90, 0x35, 0x58, 0xf0, 0xc3, 0xd8, 0x3f, 0x47, 0x46, 0x75, 0x6a, 0x00, 0xb2, 0x04,
0x55, 0x11, 0xe0, 0xce, 0x36, 0xad, 0x8a, 0x80, 0x7c, 0x0e, 0x2d, 0x3f, 0x8e, 0x14, 0xf3, 0x95,
0xec, 0xd5, 0xee, 0xd7, 0x1e, 0x75, 0x1e, 0x3f, 0xdc, 0xca, 0x34, 0xb2, 0x75, 0x34, 0x8a, 0xfc,
0xfd, 0x48, 0x2a, 0x16, 0x86, 0x78, 0xd7, 0x1d, 0x43, 0xf9, 0xd5, 0x63, 0x9a, 0x6f, 0x22, 0x1f,
0x43, 0xa7, 0x70, 0xd3, 0x5e, 0x1d, 0x79, 0xac, 0x97, 0x79, 0xec, 0x58, 0x82, 0x11, 0x2d, 0xd2,
0x92, 0xd7, 0xb0, 0x9c, 0xb1, 0xb1, 0x3a, 0xe8, 0x2d, 0xdc, 0xaf, 0x3c, 0xea, 0x3c, 0x7e, 0x77,
0xbc, 0xfd, 0x0a, 0x85, 0xd1, 0xc9, 0xdd, 0xe4, 0x04, 0x48, 0x81, 0x7f, 0xc6, 0xb3, 0x71, 0x13,
0x9e, 0x33, 0x18, 0x90, 0x0f, 0xa1, 0x99, 0xa4, 0xf1, 0x1b, 0x11, 0xf2, 0x5e, 0x13, 0x79, 0xdd,
0x1e, 0xf3, 0xca, 0x78, 0x1c, 0x1a, 0x02, 0x9a, 0x51, 0x92, 0x57, 0xb0, 0x64, 0x3f, 0x33, 0x39,
0x5a, 0x37, 0x91, 0x63, 0x62, 0x33, 0xf9, 0x00, 0x9a, 0xd6, 0x08, 0x7b, 0x6d, 0xe4, 0xf3, 0x76,
0x59, 0xc5, 0x47, 0x66, 0x91, 0x66, 0x54, 0x5a, 0xb9, 0x99, 0xd5, 0x66, 0x02, 0xc0, 0x8d, 0x94,
0x3b, 0xb1, 0x5b, 0x4b, 0x70, 0xce, 0x47, 0xda, 0x79, 0x7a, 0x9d, 0x59, 0x12, 0xbc, 0x30, 0x8b,
0x34, 0xa3, 0xd2, 0x1a, 0xb0, 0x9f, 0x99, 0x00, 0xdd, 0x1b, 0x69, 0xa0, 0xbc, 0x99, 0x6c, 0x83,
0x73, 0xc9, 0x94, 0xdf, 0x7f, 0x1d, 0x85, 0xa3, 0x6d, 0xdf, 0x8f, 0x87, 0x91, 0xea, 0x2d, 0xce,
0x12, 0xc4, 0x2e, 0xd2, 0x29, 0x72, 0xe2, 0xc1, 0xfa, 0x24, 0x2e, 0x13, 0x6d, 0xe9, 0x26, 0xa2,
0xcd, 0xe3, 0xe2, 0xfe, 0xb2, 0x0e, 0xdd, 0x57, 0xc3, 0x50, 0x89, 0xec, 0x44, 0x02, 0xf5, 0x88,
0x0d, 0x38, 0xfa, 0x60, 0x9b, 0xe2, 0x37, 0xd9, 0x84, 0xb6, 0x12, 0x03, 0x2e, 0x15, 0x1b, 0x24,
0xe8, 0x89, 0x35, 0x3a, 0x46, 0xe8, 0x55, 0x13, 0x82, 0xfc, 0x38, 0xea, 0xd5, 0x70, 0xdb, 0x18,
0x41, 0x3e, 0x07, 0xf0, 0xe3, 0x30, 0x4e, 0xbd, 0x3e, 0x93, 0x7d, 0xeb, 0x6c, 0xf7, 0xc7, 0x42,
0x17, 0xcf, 0xde, 0xda, 0xd1, 0x84, 0xcf, 0x98, 0xec, 0xd3, 0xb6, 0x9f, 0x7d, 0x92, 0xdb, 0xda,
0xdf, 0x35, 0x03, 0x11, 0xa0, 0xb3, 0xd5, 0x68, 0x13, 0xe1, 0xfd, 0x80, 0xbc, 0x07, 0xcb, 0xe7,
0x7c, 0xe4, 0xb3, 0x34, 0xf0, 0x6c, 0x88, 0x44, 0xd7, 0x69, 0xe3, 0x4b, 0x68, 0xf4, 0xa1, 0xc1,
0x92, 0x75, 0xb4, 0x04, 0x6f, 0x28, 0x02, 0xf4, 0x87, 0x36, 0x6d, 0x9c, 0xf3, 0xd1, 0x89, 0x08,
0xc8, 0xa7, 0xd0, 0x10, 0x03, 0x76, 0xc6, 0xb5, 0xad, 0x6b, 0xc9, 0xfe, 0x68, 0x8e, 0x64, 0xfb,
0x36, 0xc6, 0xee, 0x6b, 0x62, 0x6a, 0xf7, 0x90, 0x0f, 0x60, 0xd5, 0x1f, 0x4a, 0x15, 0x0f, 0xc4,
0xb7, 0x26, 0xb2, 0xa2, 0x60, 0x68, 0xee, 0x6d, 0x4a, 0x4a, 0x4b, 0x78, 0xb5, 0x8d, 0x07, 0xd0,
0xce, 0xef, 0xa8, 0xc3, 0x9d, 0x88, 0x02, 0xfe, 0x2f, 0xbd, 0xca, 0xfd, 0xda, 0xa3, 0x1a, 0x35,
0xc0, 0xc6, 0x4f, 0x2b, 0xb0, 0x58, 0x3a, 0xad, 0x28, 0x7c, 0xa5, 0x24, 0x7c, 0xf6, 0x54, 0xd5,
0xc2, 0x53, 0xf5, 0xa0, 0x99, 0xb0, 0x51, 0x18, 0xb3, 0x00, 0x9f, 0xa2, 0x4b, 0x33, 0x50, 0x1f,
0x77, 0x29, 0x02, 0xa5, 0xdf, 0x40, 0x2b, 0xd1, 0x00, 0xe4, 0x16, 0x34, 0xfa, 0x5c, 0x9c, 0xf5,
0x95, 0xd5, 0xad, 0x85, 0xc8, 0x06, 0xb4, 0xb4, 0x33, 0x4b, 0xf1, 0x2d, 0x47, 0x9d, 0xd6, 0x68,
0x0e, 0x93, 0x87, 0xb0, 0x98, 0xe2, 0x97, 0xa7, 0x58, 0x7a, 0xc6, 0x15, 0xea, 0xb4, 0x46, 0xbb,
0x06, 0x79, 0x8c, 0xb8, 0x71, 0x30, 0x6f, 0x15, 0x82, 0xb9, 0xfb, 0x5d, 0x15, 0x56, 0x5f, 0xc6,
0x3e, 0x0b, 0xed, 0xcb, 0x1c, 0x5a, 0xe1, 0xfe, 0x12, 0xea, 0xe7, 0x7c, 0x24, 0x51, 0x15, 0x9d,
0xc7, 0x0f, 0xc6, 0xaf, 0x30, 0x83, 0x78, 0xeb, 0x05, 0x1f, 0x51, 0x24, 0x27, 0x9f, 0x40, 0x77,
0xa0, 0x9f, 0x89, 0x59, 0xef, 0xaa, 0xa2, 0x4f, 0xdc, 0x9a, 0xfd, 0x88, 0xb4, 0x44, 0xab, 0x6f,
0x98, 0x30, 0x29, 0x2f, 0xe3, 0x34, 0xb0, 0x56, 0x9b, 0xc3, 0x5a, 0x8b, 0x3a, 0xb5, 0xbe, 0xe0,
0x23, 0xd4, 0x56, 0x9b, 0x66, 0x20, 0x79, 0x94, 0x9b, 0x9c, 0x15, 0xca, 0x64, 0x80, 0x36, 0x9d,
0x44, 0x6f, 0xfc, 0x29, 0xd4, 0xf4, 0x86, 0x59, 0xfe, 0x44, 0xa0, 0xae, 0x93, 0x24, 0x8a, 0xdb,
0xa5, 0xf8, 0xed, 0xfe, 0xa8, 0x02, 0x6f, 0x97, 0x2e, 0xcb, 0x79, 0xfa, 0x8c, 0x87, 0x61, 0xac,
0xad, 0xdc, 0x5a, 0xb7, 0x77, 0xc1, 0x53, 0x29, 0xe2, 0x08, 0x99, 0x2d, 0xd0, 0x25, 0x8b, 0xfe,
0xca, 0x60, 0xb5, 0xa1, 0x24, 0x9c, 0xa3, 0xa3, 0x18, 0xce, 0x0d, 0x0d, 0xee, 0x07, 0x98, 0xa7,
0xf9, 0x85, 0xf0, 0xb9, 0x87, 0xa2, 0x98, 0xdb, 0x82, 0x41, 0x1d, 0x68, 0x81, 0xc6, 0x04, 0x6a,
0x94, 0x70, 0x7b, 0x67, 0x4b, 0x70, 0x3c, 0x4a, 0x30, 0x02, 0x48, 0x71, 0x16, 0x31, 0x35, 0x4c,
0x39, 0x5e, 0xb8, 0x4b, 0xc7, 0x08, 0xf7, 0xfb, 0x0a, 0x38, 0x5a, 0xec, 0x62, 0xe6, 0x9d, 0x93,
0xcd, 0xdf, 0x83, 0x65, 0x51, 0xa0, 0xf2, 0xf2, 0xd4, 0xbe, 0x54, 0x44, 0x97, 0x64, 0x46, 0x91,
0x6a, 0x53, 0x22, 0x65, 0x8a, 0xad, 0x97, 0xad, 0x3f, 0x53, 0xd1, 0x02, 0x96, 0x1a, 0x19, 0xe8,
0xfe, 0xa2, 0x02, 0xeb, 0x73, 0x8a, 0x83, 0x6b, 0xd6, 0x1d, 0x0f, 0x61, 0xd1, 0x66, 0x38, 0x0f,
0xdd, 0xdf, 0x8a, 0xd4, 0xb5, 0x48, 0xe3, 0xab, 0xb7, 0xa1, 0xc5, 0x23, 0xe9, 0x15, 0x04, 0x6b,
0xf2, 0x48, 0xa2, 0x8e, 0x1f, 0x40, 0x37, 0x64, 0x52, 0x79, 0xc3, 0x24, 0x60, 0x8a, 0x9b, 0x58,
0x56, 0xa7, 0x1d, 0x8d, 0x3b, 0x31, 0x28, 0x7d, 0x67, 0x39, 0x92, 0x8a, 0x0f, 0x3c, 0xc5, 0xce,
0x74, 0x19, 0x50, 0xd3, 0x77, 0x36, 0xa8, 0x63, 0x76, 0x26, 0xc9, 0xbb, 0xb0, 0x14, 0x6a, 0x1b,
0xf1, 0x22, 0xe1, 0x9f, 0xe3, 0x21, 0x26, 0x9c, 0x2d, 0x22, 0xf6, 0xc0, 0x22, 0xdd, 0x7f, 0x6f,
0xc0, 0xed, 0xb9, 0x95, 0x10, 0xf9, 0x33, 0x58, 0x2b, 0x0a, 0xe2, 0xe1, 0xde, 0x70, 0x64, 0x6f,
0x4f, 0x0a, 0x02, 0xbd, 0x34, 0x2b, 0x7f, 0xc0, 0xaa, 0xd0, 0x6f, 0xcb, 0x82, 0x80, 0x07, 0x18,
0x94, 0x5b, 0xd4, 0x00, 0xda, 0x4e, 0x4e, 0xf5, 0x23, 0xf3, 0x00, 0x4b, 0x8c, 0x16, 0xcd, 0x40,
0x4d, 0x3f, 0x18, 0x6a, 0x99, 0x3a, 0x86, 0x1e, 0x01, 0x4d, 0x9f, 0xf2, 0x41, 0x7c, 0xc1, 0x03,
0xac, 0x08, 0x5a, 0x34, 0x03, 0xc9, 0x7d, 0xe8, 0xf6, 0x99, 0xf4, 0x90, 0xad, 0x37, 0x94, 0x98,
0xdf, 0x5b, 0x14, 0xfa, 0x4c, 0x6e, 0x6b, 0xd4, 0x09, 0x26, 0x89, 0x0b, 0x9e, 0x8a, 0x37, 0x59,
0xf5, 0x2d, 0x15, 0x53, 0x43, 0x93, 0xbe, 0x6b, 0x94, 0x14, 0x97, 0x8e, 0x70, 0x05, 0x8b, 0xe6,
0x74, 0x28, 0x55, 0x46, 0xb9, 0x8c, 0x94, 0x1d, 0xc4, 0x59, 0x92, 0xcf, 0xe0, 0x8e, 0xad, 0x24,
0xbd, 0x94, 0xff, 0xf3, 0x90, 0x4b, 0x65, 0x5e, 0x11, 0xb7, 0xf0, 0x9e, 0x83, 0x3b, 0x7a, 0x96,
0x84, 0x1a, 0x0a, 0x7c, 0x4c, 0xbd, 0x9f, 0xcf, 0xdf, 0x6e, 0xdc, 0x60, 0x65, 0xee, 0xf6, 0x1d,
0xf4, 0x8c, 0xcf, 0x61, 0x73, 0x72, 0xbb, 0x56, 0x87, 0xe2, 0xf6, 0x78, 0x82, 0xfb, 0x6f, 0x97,
0xf7, 0x53, 0xa4, 0x30, 0xe7, 0xcf, 0x67, 0x60, 0x04, 0x58, 0x9d, 0xcf, 0xc0, 0x48, 0xf0, 0x00,
0xba, 0x81, 0x90, 0x49, 0xc8, 0x46, 0xc6, 0xbe, 0xd6, 0xf0, 0xe9, 0x3b, 0x16, 0xa7, 0x6d, 0xcc,
0xbd, 0x9c, 0xf6, 0xf7, 0xac, 0xc4, 0x99, 0xed, 0xef, 0x53, 0x46, 0x5d, 0x9d, 0x61, 0xd4, 0x93,
0x96, 0x5b, 0x9b, 0xb2, 0x5c, 0xf7, 0x29, 0x6c, 0x4c, 0x1e, 0x7c, 0x38, 0x3c, 0x0d, 0x85, 0xbf,
0xd3, 0x67, 0xd7, 0x8c, 0x35, 0xee, 0xff, 0xd7, 0x60, 0xb1, 0xd4, 0x86, 0xfc, 0xce, 0x7d, 0x5d,
0x74, 0xcc, 0x7b, 0xd0, 0x49, 0x52, 0x71, 0xc1, 0x14, 0xf7, 0xce, 0xf9, 0xc8, 0x56, 0x00, 0x60,
0x51, 0x3a, 0x1b, 0xdd, 0xd7, 0x51, 0x55, 0xfa, 0xa9, 0x48, 0xb4, 0x5c, 0xe8, 0x97, 0x5d, 0x5a,
0x44, 0xe9, 0x82, 0xe0, 0x9b, 0x58, 0x44, 0xd6, 0x2b, 0x5b, 0xd4, 0x42, 0x3a, 0x5d, 0x1a, 0x5b,
0xe5, 0x01, 0x16, 0x04, 0x2d, 0x9a, 0xc3, 0x63, 0xa7, 0x69, 0x16, 0x9d, 0xe6, 0x35, 0x38, 0xf6,
0x75, 0xa5, 0xa7, 0x62, 0x4f, 0xf3, 0xb1, 0x55, 0xd6, 0xbb, 0xf3, 0x9a, 0x2d, 0x4b, 0x7e, 0x1c,
0x3f, 0x8f, 0x45, 0x44, 0x97, 0xd2, 0x12, 0x4c, 0x9e, 0x40, 0x2b, 0x2b, 0xf1, 0x6d, 0x4b, 0x71,
0x6f, 0x0e, 0x23, 0xdb, 0x5b, 0x48, 0x9a, 0x6f, 0xd0, 0x19, 0x8c, 0x47, 0x7e, 0x3a, 0x4a, 0x54,
0xee, 0xf4, 0x63, 0x04, 0xe6, 0xb7, 0x84, 0xfb, 0x8a, 0x8d, 0x5d, 0x7f, 0x8c, 0xd0, 0x49, 0xcb,
0x92, 0x6a, 0x07, 0xc6, 0x42, 0xa5, 0x8b, 0x9a, 0x5b, 0x1a, 0xa3, 0x5f, 0xf0, 0x91, 0xd4, 0xe5,
0xcd, 0x9d, 0x2b, 0x6e, 0x64, 0xdf, 0xab, 0x92, 0xbf, 0xd7, 0x5d, 0x80, 0x04, 0x6d, 0x03, 0x9f,
0xcb, 0xbc, 0x7f, 0xdb, 0x60, 0xf4, 0x6b, 0xe5, 0x8f, 0x5e, 0x2b, 0x3e, 0xfa, 0x15, 0x81, 0x75,
0xdd, 0xd4, 0x2d, 0x59, 0xa9, 0xdc, 0xa6, 0x0d, 0x0d, 0xee, 0x07, 0xda, 0x6e, 0xb3, 0x36, 0x71,
0xa4, 0x57, 0x1b, 0xe6, 0xe1, 0x73, 0xdc, 0x3e, 0x3e, 0xa2, 0x71, 0xdf, 0xa6, 0x39, 0x0c, 0x01,
0xf2, 0x05, 0xac, 0xa4, 0xfc, 0x82, 0xb3, 0x90, 0x07, 0x9e, 0xad, 0x9c, 0xb2, 0x5a, 0xb9, 0xd0,
0x53, 0x52, 0x4b, 0x92, 0x37, 0x32, 0x69, 0x19, 0x21, 0xdd, 0xff, 0xae, 0x82, 0x33, 0xe9, 0x16,
0xe4, 0xb3, 0x42, 0x2b, 0x3f, 0x55, 0xf9, 0xcd, 0x49, 0x60, 0x85, 0x46, 0xfe, 0x4b, 0xe8, 0x5a,
0xed, 0xe9, 0x5b, 0xca, 0x5e, 0x75, 0xb2, 0x84, 0x9f, 0xef, 0x87, 0xb4, 0x93, 0xe4, 0xdf, 0x92,
0x3c, 0x81, 0x66, 0x56, 0x41, 0xd6, 0xd0, 0xae, 0xae, 0x10, 0x23, 0xbb, 0x62, 0xb6, 0xe3, 0xf7,
0x18, 0x27, 0xb8, 0x1f, 0xc1, 0x32, 0xae, 0x6a, 0x81, 0x6c, 0x3e, 0xb9, 0x5e, 0x7c, 0xf8, 0x14,
0xd6, 0xb2, 0x8d, 0xaf, 0xcc, 0x0c, 0x47, 0x52, 0xce, 0xae, 0xbb, 0xfb, 0x6f, 0xe0, 0x96, 0xe9,
0x3a, 0x95, 0xb8, 0x10, 0x6a, 0xb4, 0xc3, 0x23, 0xc5, 0xd3, 0x2b, 0xf6, 0x3b, 0x50, 0x13, 0x81,
0x51, 0x6f, 0x97, 0xea, 0x4f, 0x77, 0xd7, 0xc4, 0xb8, 0x32, 0x87, 0x6d, 0xdf, 0xe7, 0xe8, 0x4c,
0xd7, 0xe5, 0xb2, 0x67, 0x9c, 0xa5, 0xcc, 0x65, 0x57, 0xc8, 0x81, 0x90, 0xf2, 0x06, 0x6c, 0x3c,
0x78, 0x38, 0xcd, 0xe6, 0x20, 0x56, 0xa5, 0xbc, 0xca, 0xb5, 0xaf, 0x65, 0x15, 0x0f, 0x53, 0x96,
0x67, 0xdb, 0x62, 0xb6, 0x95, 0xf6, 0x2a, 0x9d, 0xc8, 0x25, 0xe7, 0x11, 0xaa, 0xaa, 0x45, 0x9b,
0x7d, 0x26, 0x8f, 0x38, 0x8f, 0xdc, 0xff, 0xaa, 0xc0, 0xbd, 0xab, 0x4f, 0x90, 0x24, 0x84, 0xbb,
0xcc, 0x2e, 0x7b, 0x3e, 0xae, 0x7b, 0x51, 0x91, 0xc0, 0xda, 0xf7, 0xa3, 0xc9, 0xc6, 0x7f, 0x1e,
0x47, 0x7a, 0x87, 0xcd, 0x3f, 0xcd, 0xfd, 0x71, 0x1b, 0xde, 0xb9, 0x7a, 0xff, 0x54, 0xa8, 0x99,
0xea, 0xe1, 0xeb, 0xc5, 0x1e, 0xfe, 0x0d, 0xac, 0x14, 0xc5, 0x1d, 0xd7, 0xdc, 0x4b, 0x8f, 0x3f,
0xbe, 0xae, 0xc8, 0x5b, 0x45, 0x40, 0x97, 0xe8, 0xd4, 0x89, 0x26, 0x30, 0xc5, 0x00, 0x55, 0x2f,
0x05, 0x28, 0x02, 0xf5, 0x94, 0xb3, 0x2c, 0xe9, 0xe0, 0xb7, 0x16, 0x39, 0xc8, 0xac, 0xc1, 0xe6,
0x9c, 0x31, 0x42, 0x27, 0x24, 0x66, 0x2d, 0xce, 0xe6, 0x9d, 0x1c, 0xd6, 0xf5, 0x9a, 0x9d, 0x6d,
0x62, 0xfb, 0xd9, 0xa5, 0x19, 0xa8, 0xd3, 0x1b, 0x1b, 0xaa, 0x7e, 0xde, 0xa5, 0x5b, 0xc8, 0xf4,
0xb4, 0x49, 0x38, 0xca, 0x66, 0xa2, 0x98, 0x22, 0xba, 0xba, 0xa7, 0x4d, 0xc2, 0x91, 0xf5, 0xb1,
0xa9, 0x28, 0xda, 0x31, 0x65, 0x47, 0x31, 0x8a, 0xbe, 0x81, 0x95, 0x01, 0x1f, 0x9c, 0xf2, 0x54,
0xf6, 0x45, 0x92, 0x55, 0x70, 0xdd, 0x1b, 0x2a, 0xf2, 0x55, 0xce, 0xc1, 0xd4, 0x7b, 0xd4, 0x19,
0x4c, 0x60, 0xc8, 0x7f, 0x54, 0xc6, 0x35, 0xdc, 0xac, 0xf2, 0x72, 0x11, 0x8f, 0x7c, 0x7a, 0xed,
0x23, 0xb3, 0xf6, 0x60, 0xaa, 0x1c, 0xcd, 0xcb, 0xb0, 0xe9, 0x25, 0xad, 0xe6, 0x80, 0x87, 0x5c,
0xbf, 0xc0, 0x92, 0x71, 0x19, 0x0b, 0x4e, 0x38, 0xdb, 0xf2, 0x84, 0xb3, 0xb9, 0xbf, 0xaa, 0x80,
0x33, 0x69, 0x2d, 0x04, 0xa0, 0x71, 0x10, 0xeb, 0x2f, 0xe7, 0x2d, 0xb2, 0x0c, 0x9d, 0x03, 0x7e,
0xf9, 0x3a, 0xe2, 0xc7, 0xf1, 0xeb, 0x88, 0x3b, 0x15, 0xb2, 0x0e, 0xab, 0x07, 0xfc, 0xf2, 0xd0,
0x54, 0x32, 0x5f, 0xa6, 0xf1, 0x30, 0xd1, 0xc1, 0xcf, 0xa9, 0x92, 0x0e, 0x34, 0x5f, 0xf1, 0x48,
0x33, 0x71, 0x6a, 0xa4, 0x0d, 0x0b, 0x54, 0x3f, 0x98, 0x53, 0x27, 0x04, 0x96, 0x76, 0x4a, 0xf5,
0xa3, 0xb3, 0xa0, 0x99, 0xe4, 0x91, 0x78, 0x3f, 0xba, 0x10, 0x0a, 0x0f, 0x77, 0x1a, 0x64, 0x0d,
0x9c, 0xc9, 0x94, 0xed, 0x34, 0xc9, 0x3b, 0xb0, 0x91, 0x63, 0xc7, 0x4f, 0x92, 0xad, 0xb7, 0xc8,
0x2a, 0x2c, 0xe7, 0xeb, 0x2f, 0x84, 0x6e, 0x1f, 0x9c, 0xb6, 0x39, 0x63, 0x4a, 0x61, 0x0e, 0xb8,
0xff, 0x59, 0x01, 0x67, 0xf2, 0x61, 0x49, 0x0f, 0xd6, 0x26, 0x71, 0xfb, 0x41, 0xa8, 0x35, 0x70,
0x07, 0xd6, 0x27, 0x57, 0x0e, 0x79, 0x14, 0x88, 0xe8, 0xcc, 0xa9, 0x90, 0x4d, 0xe8, 0x4d, 0x2e,
0x66, 0xd1, 0xd7, 0xa9, 0xce, 0x5a, 0xdd, 0xe5, 0x7e, 0xa8, 0xcb, 0x38, 0xa7, 0xe6, 0xfe, 0x5b,
0x05, 0x6e, 0xcf, 0x7d, 0x6d, 0xad, 0xce, 0x93, 0xe8, 0x3c, 0x8a, 0x2f, 0x23, 0xe7, 0x2d, 0x0d,
0x8c, 0xcf, 0xec, 0x42, 0xab, 0x70, 0x46, 0x17, 0x5a, 0x63, 0x9e, 0x64, 0x11, 0xda, 0x3b, 0x2c,
0xf2, 0x79, 0x18, 0xf2, 0xc0, 0xa9, 0xeb, 0x7d, 0xc7, 0xba, 0x5b, 0xe1, 0x81, 0xb3, 0x40, 0x56,
0x60, 0xf1, 0x24, 0x42, 0xf0, 0xeb, 0x38, 0x55, 0xfd, 0x91, 0xd3, 0x70, 0xbf, 0xaf, 0x40, 0x57,
0xdb, 0xe3, 0xd3, 0x38, 0x3e, 0x1f, 0xb0, 0xf4, 0x7c, 0x7e, 0xa8, 0x1f, 0xa6, 0xa1, 0x4d, 0x5c,
0xfa, 0x33, 0xef, 0xf9, 0x6b, 0x85, 0x9e, 0xff, 0x0e, 0xb4, 0xb1, 0x5e, 0xf7, 0x34, 0xad, 0x09,
0x2a, 0x2d, 0x44, 0x9c, 0xa4, 0x61, 0xb1, 0x71, 0x5b, 0x28, 0x37, 0x6e, 0x77, 0x01, 0xac, 0xb1,
0x6a, 0x0b, 0x6d, 0x18, 0x0b, 0xb5, 0x98, 0x6d, 0xe5, 0xfe, 0x2b, 0xbc, 0xad, 0x25, 0xdc, 0x8b,
0xe4, 0x89, 0xe4, 0xa9, 0x3e, 0xc8, 0x4c, 0x4c, 0xe7, 0x88, 0xba, 0x01, 0xad, 0xa1, 0xa5, 0xb3,
0xf2, 0xe6, 0x30, 0x0e, 0x30, 0xfb, 0x4c, 0xe0, 0xac, 0xc3, 0x14, 0x72, 0x4d, 0x84, 0xf7, 0x4b,
0x7d, 0x65, 0xbd, 0x24, 0x9e, 0xfb, 0xdc, 0x94, 0x4b, 0x3b, 0x21, 0x67, 0xe9, 0x33, 0x21, 0x55,
0x9c, 0x8e, 0x8a, 0xc1, 0xb3, 0x52, 0x0a, 0x9e, 0x77, 0x01, 0x7c, 0x4d, 0x68, 0xee, 0x62, 0x83,
0xbb, 0xc5, 0x6c, 0x2b, 0xf7, 0x87, 0x0a, 0x10, 0xcd, 0xcc, 0x4e, 0xfc, 0x0f, 0x85, 0xaf, 0x86,
0x29, 0x9f, 0x39, 0x99, 0x2a, 0x8c, 0x0f, 0xab, 0x73, 0xc6, 0x87, 0x35, 0x1c, 0xac, 0x4c, 0x8d,
0x0f, 0xeb, 0x88, 0xce, 0xc6, 0x87, 0x77, 0xa0, 0x8d, 0x9d, 0x14, 0xce, 0x0f, 0xcd, 0x28, 0x06,
0xe7, 0x87, 0x47, 0x33, 0xe7, 0x87, 0x0d, 0x24, 0x98, 0x33, 0x3f, 0x6c, 0x16, 0xe7, 0x87, 0x7d,
0x58, 0x9d, 0xbe, 0x89, 0x9c, 0x3f, 0x22, 0xfd, 0x6b, 0x68, 0x25, 0x96, 0xc8, 0x96, 0x87, 0x9b,
0xe5, 0x90, 0x58, 0xe6, 0x44, 0x73, 0x6a, 0xf7, 0x87, 0x2a, 0x74, 0x0a, 0xb3, 0xf9, 0x39, 0xef,
0xde, 0x83, 0x26, 0x0b, 0x82, 0x94, 0x4b, 0x99, 0xe9, 0xcb, 0x82, 0x45, 0x91, 0x6a, 0x25, 0x91,
0xca, 0x35, 0xbf, 0xe9, 0xc0, 0x0a, 0x35, 0x3f, 0x81, 0x7a, 0xc2, 0x54, 0xdf, 0xd6, 0xef, 0xf8,
0x9d, 0xbf, 0x54, 0xa3, 0xf0, 0x52, 0xc5, 0xb1, 0x78, 0xd3, 0xce, 0x28, 0xed, 0x58, 0x7c, 0x0d,
0x16, 0xf8, 0x20, 0xfe, 0x46, 0x60, 0xee, 0x6b, 0x53, 0x03, 0xe8, 0xa7, 0xba, 0x64, 0x61, 0xc8,
0x95, 0x1d, 0x85, 0x58, 0x48, 0x33, 0xd7, 0x66, 0x64, 0x7b, 0x22, 0xfc, 0xc6, 0x67, 0x15, 0x41,
0xc0, 0x23, 0xdb, 0x0b, 0x59, 0xe8, 0x8a, 0x39, 0xc8, 0x06, 0xb4, 0x92, 0x58, 0x0a, 0xec, 0x2a,
0x17, 0xcd, 0xbc, 0x38, 0x83, 0xdd, 0x9f, 0x5b, 0x55, 0xda, 0xdf, 0x5b, 0xe6, 0xa8, 0xb2, 0xa0,
0xb0, 0xea, 0xcc, 0x31, 0x77, 0xad, 0x3c, 0x41, 0x2d, 0x4c, 0x2a, 0xf1, 0x1b, 0x87, 0x02, 0x3c,
0x15, 0x17, 0x3c, 0xf0, 0xde, 0xa4, 0xf1, 0xc0, 0x6a, 0xb0, 0x63, 0x71, 0x5f, 0xa4, 0xf1, 0x80,
0x3c, 0x81, 0x0d, 0xd3, 0xbe, 0x4b, 0x1e, 0x78, 0xb8, 0x60, 0xa7, 0x90, 0x38, 0x87, 0x37, 0x41,
0x60, 0x1d, 0x9b, 0x79, 0xc9, 0x83, 0xdd, 0x7c, 0x7d, 0x5f, 0x2f, 0x9b, 0x91, 0x54, 0xe4, 0x67,
0xec, 0x8d, 0xd2, 0xc1, 0xa0, 0x90, 0xfb, 0x9f, 0x63, 0x45, 0x52, 0x6c, 0x91, 0xe6, 0xfc, 0xce,
0x93, 0x93, 0xe9, 0x2d, 0x76, 0x6e, 0xac, 0x5b, 0xda, 0xda, 0xcc, 0xdf, 0xa8, 0xf4, 0x2a, 0xcd,
0xc9, 0x8a, 0x6f, 0x00, 0xe5, 0x98, 0xf1, 0xeb, 0x8a, 0x09, 0x1a, 0x47, 0xec, 0x82, 0x07, 0xdb,
0xd6, 0x0e, 0x0b, 0x16, 0x5a, 0x29, 0x5b, 0xe8, 0xac, 0x9f, 0x0f, 0x36, 0xa1, 0xfd, 0x86, 0x5d,
0xc4, 0xc3, 0x54, 0x28, 0xa3, 0xf0, 0x16, 0x1d, 0x23, 0xae, 0x88, 0xa6, 0x0f, 0xa0, 0x6b, 0xb2,
0xbb, 0x57, 0x74, 0xda, 0x8e, 0xc1, 0x99, 0x99, 0xcd, 0x9f, 0xc0, 0x8a, 0x09, 0x83, 0xb2, 0x1f,
0xa7, 0x0a, 0xdb, 0x57, 0x69, 0x2d, 0x74, 0x19, 0x17, 0x8e, 0x34, 0x5e, 0xb7, 0xb1, 0x52, 0x47,
0x7e, 0x1e, 0x49, 0x5b, 0xa2, 0xe9, 0x4f, 0x6d, 0x1d, 0x42, 0x7a, 0x8a, 0xcb, 0xcc, 0x50, 0x1b,
0x42, 0x1e, 0x73, 0xa9, 0x9e, 0xd7, 0x5b, 0x75, 0x67, 0xc1, 0xfd, 0xae, 0x62, 0xe2, 0xf5, 0xd4,
0x04, 0x60, 0x8e, 0xb1, 0x4d, 0x56, 0x72, 0xd5, 0xe9, 0x4a, 0x6e, 0x0f, 0xee, 0xf5, 0x4d, 0xe0,
0xf5, 0x58, 0xea, 0xf7, 0xc5, 0x05, 0xf7, 0xe4, 0x30, 0x49, 0xb4, 0xec, 0x3c, 0x62, 0xa7, 0xa1,
0x9d, 0xfe, 0xb4, 0xe8, 0xa6, 0x25, 0xdb, 0x36, 0x54, 0x47, 0x86, 0x68, 0xcf, 0xd0, 0xb8, 0xff,
0x57, 0x31, 0x4d, 0x9e, 0x4d, 0x88, 0x3a, 0x9b, 0x5c, 0x73, 0xe0, 0xfc, 0x19, 0x34, 0x6c, 0x31,
0x67, 0x0a, 0xf1, 0x89, 0xa9, 0x49, 0x81, 0xe1, 0xd6, 0xf1, 0x78, 0x36, 0x48, 0xed, 0x26, 0xf7,
0x13, 0xe8, 0x14, 0xd0, 0x98, 0xd8, 0x0f, 0x5e, 0x1c, 0xbc, 0xfe, 0xfa, 0xc0, 0x24, 0xf6, 0x63,
0x7a, 0x72, 0x74, 0xbc, 0xb7, 0xeb, 0x54, 0x30, 0x41, 0x1f, 0x20, 0xf8, 0xf5, 0x6b, 0x7a, 0xfc,
0xec, 0xef, 0x9d, 0xaa, 0xfb, 0x7d, 0xcd, 0x4c, 0xcf, 0x8a, 0x05, 0x82, 0xad, 0x7b, 0xe6, 0x08,
0x4f, 0xa0, 0x8e, 0x5e, 0x61, 0x8d, 0x49, 0x7f, 0xeb, 0x0b, 0xa9, 0xd8, 0xba, 0x6d, 0x55, 0xc5,
0xda, 0xb8, 0xfc, 0xbe, 0x0e, 0x3a, 0xd1, 0x59, 0xe6, 0xb9, 0x63, 0x84, 0x7e, 0x12, 0x3b, 0xef,
0x31, 0x69, 0xcc, 0x0e, 0x85, 0x73, 0xdc, 0x36, 0xfe, 0x64, 0x93, 0x72, 0x99, 0xc4, 0x91, 0xcc,
0x62, 0x61, 0x0e, 0xeb, 0xb0, 0xaa, 0x6b, 0x75, 0x61, 0x36, 0x1b, 0xfb, 0x6b, 0x5b, 0xcc, 0xb6,
0x22, 0x7c, 0xf6, 0x14, 0xb6, 0x85, 0x9a, 0xfd, 0x8b, 0xb2, 0x66, 0x67, 0xdc, 0x7a, 0x6b, 0x46,
0x61, 0x3c, 0x6b, 0x76, 0x6b, 0xde, 0xb0, 0x9d, 0xb7, 0xda, 0x7f, 0x07, 0x64, 0x4e, 0x91, 0x55,
0x7c, 0x8b, 0xc3, 0xbd, 0x83, 0xdd, 0xfd, 0x83, 0x2f, 0x6d, 0x91, 0xb5, 0xb3, 0xb3, 0x77, 0xa8,
0x5f, 0xc6, 0x14, 0x59, 0x7b, 0x3b, 0x2f, 0xf7, 0x0f, 0xf6, 0x76, 0x9d, 0x9a, 0x86, 0x76, 0xb6,
0x0f, 0x76, 0xf6, 0x5e, 0xee, 0xed, 0x3a, 0x75, 0xf7, 0x67, 0x15, 0xd3, 0x83, 0x97, 0x8b, 0xdc,
0x5d, 0xee, 0x0b, 0x39, 0xff, 0xd7, 0x97, 0x4d, 0x68, 0x5b, 0x7d, 0xee, 0x67, 0x96, 0x36, 0x46,
0x90, 0x7f, 0x84, 0xe5, 0xc0, 0xee, 0xf7, 0x4a, 0x96, 0xf7, 0xe1, 0xe4, 0x34, 0x63, 0xd6, 0x91,
0x5b, 0xd9, 0x87, 0x55, 0xcf, 0x52, 0x50, 0x82, 0xdd, 0xf7, 0x61, 0xa9, 0x4c, 0x51, 0xba, 0xec,
0x5b, 0xa5, 0xcb, 0x56, 0xdc, 0x9f, 0x54, 0x61, 0x79, 0xe2, 0x3f, 0x15, 0xe6, 0x67, 0xf9, 0xc9,
0x71, 0x70, 0x75, 0x6a, 0x1c, 0x4c, 0xde, 0x07, 0x52, 0x24, 0xf1, 0x8a, 0x73, 0x35, 0xa7, 0x40,
0x68, 0x62, 0x55, 0xb1, 0x6c, 0xa8, 0xdf, 0xa4, 0x6c, 0x20, 0x9f, 0x42, 0x57, 0xc6, 0xbe, 0x60,
0xa1, 0x17, 0x8a, 0xe8, 0x3c, 0xfb, 0xf7, 0x90, 0xdb, 0x13, 0xff, 0xfa, 0x80, 0x14, 0x2f, 0x35,
0x01, 0xed, 0xc8, 0x31, 0x40, 0xfe, 0x16, 0xd6, 0x78, 0x24, 0xbd, 0xac, 0x74, 0xf4, 0x82, 0xfc,
0x1f, 0x42, 0x6a, 0xd3, 0xd3, 0xce, 0xa9, 0xda, 0x94, 0x12, 0x3e, 0x89, 0x92, 0xae, 0x04, 0xa0,
0xec, 0x32, 0xeb, 0x60, 0x0b, 0xf5, 0x5d, 0xa5, 0x5c, 0xdf, 0xbd, 0x80, 0x8e, 0x6d, 0x7d, 0x75,
0x0b, 0x86, 0x2a, 0x5c, 0x7a, 0xfc, 0xc7, 0xe3, 0x13, 0xb7, 0xc7, 0xff, 0x40, 0xf4, 0xca, 0xfe,
0xff, 0x90, 0x65, 0xba, 0x85, 0xbd, 0x7e, 0x71, 0xb7, 0xfb, 0xbf, 0x15, 0x58, 0xd2, 0x22, 0x16,
0x4e, 0xfe, 0x2b, 0xe8, 0xa4, 0x39, 0x94, 0x8d, 0x43, 0xd6, 0x0a, 0x23, 0xc4, 0x7c, 0x91, 0x16,
0x09, 0xc9, 0x63, 0x58, 0x93, 0xc3, 0xd3, 0x6c, 0x8e, 0xf8, 0x5c, 0xc6, 0xd1, 0xd3, 0x91, 0xe2,
0x59, 0xb9, 0x35, 0x73, 0x8d, 0xbc, 0x0f, 0x2b, 0xd9, 0xdc, 0x77, 0xbc, 0xc1, 0x0c, 0xc3, 0xa7,
0x17, 0xdc, 0xff, 0xa9, 0xe4, 0xe5, 0x89, 0xce, 0xb0, 0xd8, 0x76, 0xe4, 0x26, 0xa6, 0x3f, 0x67,
0x66, 0xca, 0x5b, 0xd0, 0xb0, 0xbf, 0x20, 0x99, 0x2c, 0x60, 0xa1, 0xa2, 0x91, 0xd6, 0x4b, 0x46,
0xba, 0x09, 0x6d, 0x9b, 0x79, 0xb9, 0x36, 0x8b, 0x9a, 0x2e, 0xfb, 0x72, 0x44, 0xa9, 0x7e, 0x32,
0x75, 0xc8, 0xb8, 0x7e, 0xfa, 0x27, 0x93, 0x41, 0x0a, 0x56, 0x43, 0x3e, 0x9a, 0x30, 0xb3, 0x29,
0x75, 0x8e, 0x89, 0xcb, 0x16, 0x96, 0xc7, 0x85, 0x6a, 0x21, 0x2e, 0x3c, 0x5d, 0xfc, 0x87, 0xce,
0xd6, 0x07, 0x4f, 0xb2, 0xcd, 0xa7, 0x0d, 0xfc, 0xfa, 0xf0, 0xb7, 0x01, 0x00, 0x00, 0xff, 0xff,
0x17, 0xe1, 0xf7, 0xaf, 0x79, 0x26, 0x00, 0x00,
}

View File

@ -402,24 +402,7 @@ message SyncKeycard {
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;
}
uint64 position = 6;
}
message SyncSocialLinks {

View File

@ -320,8 +320,6 @@ 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_KEYCARD_ACTION:
return m.unmarshalProtobufData(new(protobuf.SyncKeycardAction))
case protobuf.ApplicationMetadataMessage_SYNC_SOCIAL_LINKS:
return m.unmarshalProtobufData(new(protobuf.SyncSocialLinks))
case protobuf.ApplicationMetadataMessage_SYNC_ENS_USERNAME_DETAIL:

View File

@ -4,7 +4,6 @@ import (
"context"
"errors"
"strings"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
@ -52,7 +51,7 @@ func (api *API) SaveAccount(ctx context.Context, account *accounts.Account) erro
return nil
}
// Setting `Keypair` without `Accounts` will update keypair only.
// Setting `Keypair` without `Accounts` will update keypair only, `Keycards` won't be saved/updated this way.
func (api *API) SaveKeypair(ctx context.Context, keypair *accounts.Keypair) error {
log.Info("[AccountsAPI::SaveKeypair]")
err := (*api.messenger).SaveOrUpdateKeypair(keypair)
@ -327,13 +326,14 @@ func (api *API) VerifyPassword(password string) bool {
}
// If keypair is migrated from keycard to app, then `accountsComingFromKeycard` should be set to true, otherwise false.
func (api *API) AddKeycardOrAddAccountsIfKeycardIsAdded(ctx context.Context, kcUID string, kpName string, keyUID string,
accountAddresses []string, accountsComingFromKeycard bool) error {
if len(accountAddresses) == 0 {
// If keycard is new `Position` will be determined and set by the backend and `KeycardLocked` will be set to false.
// If keycard is already added, `Position` and `KeycardLocked` will be unchanged.
func (api *API) SaveOrUpdateKeycard(ctx context.Context, keycard *accounts.Keycard, accountsComingFromKeycard bool) error {
if len(keycard.AccountsAddresses) == 0 {
return errors.New("cannot migrate a keypair without accounts")
}
kpDb, err := api.db.GetKeypairByKeyUID(keyUID)
kpDb, err := api.db.GetKeypairByKeyUID(keycard.KeyUID)
if err != nil {
if err == accounts.ErrDbKeypairNotFound {
return errors.New("cannot migrate an unknown keypair")
@ -341,23 +341,12 @@ func (api *API) AddKeycardOrAddAccountsIfKeycardIsAdded(ctx context.Context, kcU
return err
}
kp := accounts.Keycard{
KeycardUID: kcUID,
KeycardName: kpName,
KeycardLocked: false,
KeyUID: keyUID,
LastUpdateClock: uint64(time.Now().Unix()),
}
for _, addr := range accountAddresses {
kp.AccountsAddresses = append(kp.AccountsAddresses, types.Address(common.HexToAddress(addr)))
}
knownKeycardsForKeyUID, err := api.db.GetKeycardByKeyUID(keyUID)
relatedKeycardsByKeyUID, err := api.db.GetKeycardsWithSameKeyUID(keycard.KeyUID)
if err != nil {
return err
}
added, err := (*api.messenger).AddKeycardOrAddAccountsIfKeycardIsAdded(ctx, &kp)
err = (*api.messenger).SaveOrUpdateKeycard(ctx, keycard)
if err != nil {
return err
}
@ -365,8 +354,8 @@ func (api *API) AddKeycardOrAddAccountsIfKeycardIsAdded(ctx context.Context, kcU
if !accountsComingFromKeycard {
// Once we migrate a keypair, corresponding keystore files need to be deleted
// if the keypair being migrated is not already migrated (in case user is creating a copy of an existing Keycard)
if added && len(knownKeycardsForKeyUID) == 0 {
for _, addr := range kp.AccountsAddresses {
if len(relatedKeycardsByKeyUID) == 0 {
for _, addr := range keycard.AccountsAddresses {
err = api.manager.DeleteAccount(addr)
if err != nil {
return err
@ -383,52 +372,42 @@ func (api *API) AddKeycardOrAddAccountsIfKeycardIsAdded(ctx context.Context, kcU
return nil
}
func (api *API) RemoveMigratedAccountsForKeycard(ctx context.Context, kcUID string, accountAddresses []string) error {
clock := uint64(time.Now().Unix())
var addresses []types.Address
for _, addr := range accountAddresses {
addresses = append(addresses, types.HexToAddress(addr))
}
return (*api.messenger).RemoveMigratedAccountsForKeycard(ctx, kcUID, addresses, clock)
}
func (api *API) GetAllKnownKeycards(ctx context.Context) ([]*accounts.Keycard, error) {
return api.db.GetAllKnownKeycards()
}
func (api *API) GetAllKnownKeycardsGroupedByKeyUID(ctx context.Context) ([]*accounts.Keycard, error) {
return api.db.GetAllKnownKeycardsGroupedByKeyUID()
func (api *API) GetKeycardsWithSameKeyUID(ctx context.Context, keyUID string) ([]*accounts.Keycard, error) {
return api.db.GetKeycardsWithSameKeyUID(keyUID)
}
func (api *API) GetKeycardByKeyUID(ctx context.Context, keyUID string) ([]*accounts.Keycard, error) {
return api.db.GetKeycardByKeyUID(keyUID)
func (api *API) GetKeycardByKeycardUID(ctx context.Context, keycardUID string) (*accounts.Keycard, error) {
return api.db.GetKeycardByKeycardUID(keycardUID)
}
func (api *API) SetKeycardName(ctx context.Context, kcUID string, kpName string) error {
clock := uint64(time.Now().Unix())
return (*api.messenger).SetKeycardName(ctx, kcUID, kpName, clock)
func (api *API) SetKeycardName(ctx context.Context, keycardUID string, kpName string) error {
return (*api.messenger).SetKeycardName(ctx, keycardUID, kpName)
}
func (api *API) KeycardLocked(ctx context.Context, kcUID string) error {
clock := uint64(time.Now().Unix())
return (*api.messenger).KeycardLocked(ctx, kcUID, clock)
func (api *API) KeycardLocked(ctx context.Context, keycardUID string) error {
return (*api.messenger).KeycardLocked(ctx, keycardUID)
}
func (api *API) KeycardUnlocked(ctx context.Context, kcUID string) error {
clock := uint64(time.Now().Unix())
return (*api.messenger).KeycardUnlocked(ctx, kcUID, clock)
func (api *API) KeycardUnlocked(ctx context.Context, keycardUID string) error {
return (*api.messenger).KeycardUnlocked(ctx, keycardUID)
}
func (api *API) DeleteKeycard(ctx context.Context, kcUID string) error {
clock := uint64(time.Now().Unix())
return (*api.messenger).DeleteKeycard(ctx, kcUID, clock)
func (api *API) DeleteKeycardAccounts(ctx context.Context, keycardUID string, accountAddresses []types.Address) error {
return (*api.messenger).DeleteKeycardAccounts(ctx, keycardUID, accountAddresses)
}
func (api *API) DeleteKeycard(ctx context.Context, keycardUID string) error {
return (*api.messenger).DeleteKeycard(ctx, keycardUID)
}
func (api *API) DeleteAllKeycardsWithKeyUID(ctx context.Context, keyUID string) error {
return api.db.DeleteAllKeycardsWithKeyUID(keyUID)
return (*api.messenger).DeleteAllKeycardsWithKeyUID(ctx, keyUID)
}
func (api *API) UpdateKeycardUID(ctx context.Context, oldKcUID string, newKcUID string) error {
clock := uint64(time.Now().Unix())
return (*api.messenger).UpdateKeycardUID(ctx, oldKcUID, newKcUID, clock)
func (api *API) UpdateKeycardUID(ctx context.Context, oldKeycardUID string, newKeycardUID string) error {
return (*api.messenger).UpdateKeycardUID(ctx, oldKeycardUID, newKeycardUID)
}