From eeaaf0ce3f1faf83471b8bc5756ad169a42b2a0b Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Tue, 16 May 2023 12:48:00 +0200 Subject: [PATCH] feat: accounts improvements applied - old `accounts` table is moved/mapped to `keypairs` and `keypairs_accounts` - `keycards` table has foreign key which refers to `keypairs.key_uid` - `Keypair` introduced as a new type - api endpoints updated according to this change --- VERSION | 2 +- api/geth_backend.go | 37 +- appdatabase/migrations/bindata.go | 148 ++- ..._accounts_and_keycards_improvements.up.sql | 94 ++ multiaccounts/accounts/database.go | 1084 ++++++++++++----- .../keycard_database.go} | 82 +- protocol/messenger.go | 89 +- protocol/messenger_backup.go | 77 +- protocol/messenger_backup_handler.go | 79 +- protocol/messenger_config.go | 3 +- protocol/messenger_handler.go | 254 +++- protocol/messenger_keycard.go | 91 +- protocol/messenger_response.go | 35 +- protocol/messenger_sync_raw_messages.go | 29 +- protocol/messenger_wallet.go | 184 ++- .../application_metadata_message.pb.go | 135 +- .../application_metadata_message.proto | 5 +- protocol/protobuf/pairing.pb.go | 882 +++++++------- protocol/protobuf/pairing.proto | 56 +- protocol/v1/status_message.go | 10 +- protocol/wakusync/response.go | 23 +- server/pairing/payload_management.go | 12 +- server/pairing/payload_mounter.go | 2 +- server/pairing/raw_message_handler.go | 6 +- services/accounts/accounts.go | 247 ++-- services/accounts/service.go | 4 +- services/ext/signal.go | 8 +- services/wallet/api.go | 6 +- services/web3provider/api_test.go | 2 +- signal/events_sync_from_waku.go | 15 +- 30 files changed, 2323 insertions(+), 1378 deletions(-) create mode 100644 appdatabase/migrations/sql/1683627613_accounts_and_keycards_improvements.up.sql rename multiaccounts/{keycards/database.go => accounts/keycard_database.go} (90%) diff --git a/VERSION b/VERSION index a30a0fd99..7b3c89d92 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.152.0 +0.152.1 \ No newline at end of file diff --git a/api/geth_backend.go b/api/geth_backend.go index 16aed5ff9..fb2845d89 100644 --- a/api/geth_backend.go +++ b/api/geth_backend.go @@ -29,7 +29,6 @@ import ( "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/multiaccounts" "github.com/status-im/status-go/multiaccounts/accounts" - "github.com/status-im/status-go/multiaccounts/keycards" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/node" "github.com/status-im/status-go/nodecfg" @@ -619,6 +618,15 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun if err != nil { return err } + + keypair, err := accountDB.GetKeypairByKeyUID(account.KeyUID) + if err != nil { + if err == accounts.ErrDbKeypairNotFound { + return errors.New("cannot convert an unknown keypair") + } + return err + } + err = accountDB.SaveSettingField(settings.KeycardInstanceUID, s.KeycardInstanceUID) if err != nil { return err @@ -639,11 +647,6 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun return err } - relatedAccounts, err := accountDB.GetAccountsByKeyUID(account.KeyUID) - if err != nil { - return err - } - // This check is added due to mobile app cause it doesn't support a Keycard features as desktop app. // We should remove the following line once mobile and desktop app align. if len(keycardUID) > 0 { @@ -652,7 +655,7 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun return err } - kc := keycards.Keycard{ + kc := accounts.Keycard{ KeycardUID: keycardUID, KeycardName: displayName, KeycardLocked: false, @@ -660,7 +663,7 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun LastUpdateClock: uint64(time.Now().Unix()), } - for _, acc := range relatedAccounts { + for _, acc := range keypair.Accounts { kc.AccountsAddresses = append(kc.AccountsAddresses, acc.Address) } addedKc, _, err := accountDB.AddKeycardOrAddAccountsIfKeycardIsAdded(kc) @@ -698,7 +701,7 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun } // We need to delete all accounts for the Keycard which is being added - for _, acc := range relatedAccounts { + for _, acc := range keypair.Accounts { err = b.accountManager.DeleteAccount(acc.Address) if err != nil { return err @@ -1058,6 +1061,7 @@ func (b *GethStatusBackend) StartNodeWithAccountAndInitialConfig( return b.StartNodeWithAccount(account, password, nodecfg) } +// TODO: change in `saveAccountsAndSettings` function param `subaccs []*accounts.Account` parameter to `profileKeypair *accounts.Keypair` parameter func (b *GethStatusBackend) saveAccountsAndSettings(settings settings.Settings, nodecfg *params.NodeConfig, subaccs []*accounts.Account) error { b.mu.Lock() defer b.mu.Unlock() @@ -1079,7 +1083,20 @@ func (b *GethStatusBackend) saveAccountsAndSettings(settings settings.Settings, return err } - return accdb.SaveAccounts(subaccs) + keypair := &accounts.Keypair{ + KeyUID: settings.KeyUID, + Name: settings.DisplayName, + Type: accounts.KeypairTypeProfile, + DerivedFrom: settings.Address.String(), + LastUsedDerivationIndex: 0, + } + + for _, acc := range subaccs { + acc.Operable = accounts.AccountFullyOperable + keypair.Accounts = append(keypair.Accounts, acc) + } + + return accdb.SaveOrUpdateKeypair(keypair) } func (b *GethStatusBackend) loadNodeConfig(inputNodeCfg *params.NodeConfig) error { diff --git a/appdatabase/migrations/bindata.go b/appdatabase/migrations/bindata.go index 048c1395d..b03cbfe99 100644 --- a/appdatabase/migrations/bindata.go +++ b/appdatabase/migrations/bindata.go @@ -61,6 +61,7 @@ // 1682146075_add_created_at_to_saved_addresses.up.sql (107B) // 1682393575_sync_ens_name.up.sql (713B) // 1683457503_add_blocks_ranges_sequential_table.up.sql (263B) +// 1683627613_accounts_and_keycards_improvements.up.sql (3.64kB) // doc.go (74B) package migrations @@ -145,7 +146,7 @@ func _1640111208_dummyUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1640111208_dummy.up.sql", size: 258, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1640111208_dummy.up.sql", size: 258, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xf0, 0xae, 0x20, 0x6e, 0x75, 0xd1, 0x36, 0x14, 0xf2, 0x40, 0xe5, 0xd6, 0x7a, 0xc4, 0xa5, 0x72, 0xaa, 0xb5, 0x4d, 0x71, 0x97, 0xb8, 0xe8, 0x95, 0x22, 0x95, 0xa2, 0xac, 0xaf, 0x48, 0x58}} return a, nil } @@ -165,7 +166,7 @@ func _1642666031_add_removed_clock_to_bookmarksUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1642666031_add_removed_clock_to_bookmarks.up.sql", size: 117, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1642666031_add_removed_clock_to_bookmarks.up.sql", size: 117, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x84, 0x4e, 0x38, 0x99, 0x7a, 0xc, 0x90, 0x13, 0xec, 0xfe, 0x2f, 0x55, 0xff, 0xb7, 0xb6, 0xaa, 0x96, 0xc6, 0x92, 0x79, 0xcc, 0xee, 0x4e, 0x99, 0x53, 0xfe, 0x1c, 0xbb, 0x32, 0x2, 0xa4, 0x27}} return a, nil } @@ -185,7 +186,7 @@ func _1643644541_gif_api_key_settingUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1643644541_gif_api_key_setting.up.sql", size: 108, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1643644541_gif_api_key_setting.up.sql", size: 108, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1b, 0x94, 0x28, 0xfb, 0x66, 0xd1, 0x7c, 0xb8, 0x89, 0xe2, 0xb4, 0x71, 0x65, 0x24, 0x57, 0x22, 0x95, 0x38, 0x97, 0x3, 0x9b, 0xc6, 0xa4, 0x41, 0x7b, 0xba, 0xf7, 0xdb, 0x70, 0xf7, 0x20, 0x3a}} return a, nil } @@ -205,7 +206,7 @@ func _1644188994_recent_stickersUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1644188994_recent_stickers.up.sql", size: 79, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1644188994_recent_stickers.up.sql", size: 79, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1e, 0xad, 0xaa, 0x30, 0xbf, 0x4, 0x7, 0xf8, 0xc3, 0x3, 0xb8, 0x97, 0x23, 0x2b, 0xbd, 0x1c, 0x60, 0x69, 0xb0, 0x42, 0x5e, 0x6b, 0xd, 0xa7, 0xa3, 0x6b, 0x2e, 0xdc, 0x70, 0x13, 0x72, 0x7}} return a, nil } @@ -225,7 +226,7 @@ func _1646659233_add_address_to_dapp_permisssionUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1646659233_add_address_to_dapp_permisssion.up.sql", size: 700, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1646659233_add_address_to_dapp_permisssion.up.sql", size: 700, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xed, 0xb0, 0x35, 0xcc, 0x2e, 0x16, 0xe6, 0x15, 0x86, 0x2c, 0x37, 0x80, 0xae, 0xa3, 0xc5, 0x31, 0x78, 0x5, 0x9d, 0xcd, 0x7b, 0xeb, 0x5f, 0xf2, 0xb3, 0x74, 0x72, 0xdf, 0xcf, 0x88, 0xb, 0x40}} return a, nil } @@ -245,7 +246,7 @@ func _1646841105_add_emoji_accountUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1646841105_add_emoji_account.up.sql", size: 96, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1646841105_add_emoji_account.up.sql", size: 96, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe6, 0x77, 0x29, 0x95, 0x18, 0x64, 0x82, 0x63, 0xe7, 0xaf, 0x6c, 0xa9, 0x15, 0x7d, 0x46, 0xa6, 0xbc, 0xdf, 0xa7, 0xd, 0x2b, 0xd2, 0x2d, 0x97, 0x4d, 0xa, 0x6b, 0xd, 0x6e, 0x90, 0x42, 0x5c}} return a, nil } @@ -265,7 +266,7 @@ func _1647278782_display_nameUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1647278782_display_name.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1647278782_display_name.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xa1, 0x1f, 0x3e, 0x61, 0x65, 0x8d, 0xff, 0xee, 0xde, 0xc5, 0x91, 0xd9, 0x5c, 0xb5, 0xe2, 0xf0, 0xb7, 0xe7, 0x5c, 0x5c, 0x16, 0x25, 0x89, 0xee, 0x78, 0x12, 0xea, 0x3e, 0x48, 0x41, 0xa6}} return a, nil } @@ -285,7 +286,7 @@ func _1647862838_reset_last_backupUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1647862838_reset_last_backup.up.sql", size: 37, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1647862838_reset_last_backup.up.sql", size: 37, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x21, 0xe3, 0xd5, 0xf6, 0x5f, 0xfe, 0x65, 0xfa, 0x1d, 0x88, 0xf8, 0x5f, 0x24, 0x71, 0x34, 0x68, 0x96, 0x2a, 0x60, 0x87, 0x15, 0x82, 0x4d, 0x8a, 0x59, 0x3d, 0x1f, 0xd8, 0x56, 0xd4, 0xfb, 0xda}} return a, nil } @@ -305,7 +306,7 @@ func _1647871652_add_settings_sync_clock_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1647871652_add_settings_sync_clock_table.up.sql", size: 1044, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1647871652_add_settings_sync_clock_table.up.sql", size: 1044, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd8, 0x58, 0xec, 0x85, 0x90, 0xfa, 0x30, 0x98, 0x98, 0x9a, 0xa6, 0xa8, 0x96, 0x2b, 0x38, 0x93, 0xf3, 0xae, 0x46, 0x74, 0xa4, 0x41, 0x62, 0x9b, 0x2, 0x86, 0xbf, 0xe5, 0x2a, 0xce, 0xe2, 0xc0}} return a, nil } @@ -325,7 +326,7 @@ func _1647880168_add_torrent_configUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1647880168_add_torrent_config.up.sql", size: 211, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1647880168_add_torrent_config.up.sql", size: 211, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0x92, 0x22, 0x37, 0x96, 0xf3, 0xb5, 0x5b, 0x27, 0xd0, 0x7d, 0x43, 0x5, 0x4e, 0x9d, 0xe2, 0x49, 0xbe, 0x86, 0x31, 0xa1, 0x89, 0xff, 0xd6, 0x51, 0xe0, 0x9c, 0xb, 0xda, 0xfc, 0xf2, 0x93}} return a, nil } @@ -345,7 +346,7 @@ func _1647882837_add_communities_settings_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1647882837_add_communities_settings_table.up.sql", size: 206, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)} + info := bindataFileInfo{name: "1647882837_add_communities_settings_table.up.sql", size: 206, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbd, 0x87, 0x78, 0x99, 0xd9, 0x5d, 0xbd, 0xf7, 0x57, 0x9c, 0xca, 0x97, 0xbd, 0xb3, 0xe9, 0xb5, 0x89, 0x31, 0x3f, 0xf6, 0x5c, 0x13, 0xb, 0xc3, 0x54, 0x93, 0x18, 0x40, 0x7, 0x82, 0xfe, 0x7e}} return a, nil } @@ -365,7 +366,7 @@ func _1647956635_add_waku_messages_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1647956635_add_waku_messages_table.up.sql", size: 266, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1647956635_add_waku_messages_table.up.sql", size: 266, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0xe, 0xe1, 0xdc, 0xda, 0x2e, 0x89, 0x8d, 0xdc, 0x2a, 0x1c, 0x13, 0xa1, 0xfc, 0xfe, 0xf, 0xb2, 0xb9, 0x85, 0xc8, 0x45, 0xd6, 0xd1, 0x7, 0x5c, 0xa3, 0x8, 0x47, 0x44, 0x6d, 0x96, 0xe0}} return a, nil } @@ -385,7 +386,7 @@ func _1648554928_network_testUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1648554928_network_test.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1648554928_network_test.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9a, 0xc5, 0x7f, 0x87, 0xf3, 0x2c, 0xf7, 0xbb, 0xd3, 0x3a, 0x4e, 0x76, 0x88, 0xca, 0xaf, 0x73, 0xce, 0x8f, 0xa1, 0xf6, 0x3d, 0x4d, 0xed, 0x6f, 0x49, 0xf2, 0xfe, 0x56, 0x2a, 0x60, 0x68, 0xca}} return a, nil } @@ -405,7 +406,7 @@ func _1649174829_add_visitble_tokenUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1649174829_add_visitble_token.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1649174829_add_visitble_token.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa3, 0x22, 0xc0, 0x2b, 0x3f, 0x4f, 0x3d, 0x5e, 0x4c, 0x68, 0x7c, 0xd0, 0x15, 0x36, 0x9f, 0xec, 0xa1, 0x2a, 0x7b, 0xb4, 0xe3, 0xc6, 0xc9, 0xb4, 0x81, 0x50, 0x4a, 0x11, 0x3b, 0x35, 0x7, 0xcf}} return a, nil } @@ -425,7 +426,7 @@ func _1649882262_add_derived_from_accountsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1649882262_add_derived_from_accounts.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1649882262_add_derived_from_accounts.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x11, 0xb9, 0x44, 0x4d, 0x85, 0x8d, 0x7f, 0xb4, 0xae, 0x4f, 0x5c, 0x66, 0x64, 0xb6, 0xe2, 0xe, 0x3d, 0xad, 0x9d, 0x8, 0x4f, 0xab, 0x6e, 0xa8, 0x7d, 0x76, 0x3, 0xad, 0x96, 0x1, 0xee, 0x5c}} return a, nil } @@ -445,7 +446,7 @@ func _1650612625_add_community_message_archive_hashes_tableUpSql() (*asset, erro return nil, err } - info := bindataFileInfo{name: "1650612625_add_community_message_archive_hashes_table.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1650612625_add_community_message_archive_hashes_table.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x48, 0x31, 0xb3, 0x75, 0x23, 0xe2, 0x45, 0xe, 0x47, 0x1b, 0x35, 0xa5, 0x6e, 0x83, 0x4e, 0x64, 0x7d, 0xd7, 0xa2, 0xda, 0xe9, 0x53, 0xf1, 0x16, 0x86, 0x2c, 0x57, 0xad, 0xfa, 0xca, 0x39, 0xde}} return a, nil } @@ -465,7 +466,7 @@ func _1650616788_add_communities_archives_info_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1650616788_add_communities_archives_info_table.up.sql", size: 208, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1650616788_add_communities_archives_info_table.up.sql", size: 208, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0x4f, 0x80, 0x45, 0xb9, 0xd9, 0x15, 0xe2, 0x78, 0xd0, 0xcb, 0x71, 0xc1, 0x1b, 0xb7, 0x1b, 0x1b, 0x97, 0xfe, 0x47, 0x53, 0x3c, 0x62, 0xbc, 0xdd, 0x3a, 0x94, 0x1a, 0xc, 0x48, 0x76, 0xe}} return a, nil } @@ -485,7 +486,7 @@ func _1652715604_add_clock_accountsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1652715604_add_clock_accounts.up.sql", size: 62, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1652715604_add_clock_accounts.up.sql", size: 62, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb6, 0xd9, 0x8d, 0x73, 0xc9, 0xef, 0xfa, 0xb1, 0x4b, 0xa5, 0xf3, 0x5, 0x19, 0x26, 0x46, 0xf8, 0x47, 0x93, 0xdb, 0xac, 0x2, 0xef, 0xf9, 0x71, 0x56, 0x83, 0xe6, 0x2d, 0xb0, 0xd7, 0x83, 0x5c}} return a, nil } @@ -505,7 +506,7 @@ func _1653037334_add_notifications_settings_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1653037334_add_notifications_settings_table.up.sql", size: 1276, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1653037334_add_notifications_settings_table.up.sql", size: 1276, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4b, 0xc4, 0x65, 0xac, 0xa, 0xf2, 0xef, 0xb6, 0x39, 0x3c, 0xc5, 0xb1, 0xb2, 0x9c, 0x86, 0x58, 0xe0, 0x38, 0xcb, 0x57, 0x3c, 0x76, 0x73, 0x87, 0x79, 0x4e, 0xf6, 0xed, 0xb0, 0x8e, 0x9e, 0xa}} return a, nil } @@ -525,7 +526,7 @@ func _1654702119_add_mutual_contact_settingsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1654702119_add_mutual_contact_settings.up.sql", size: 78, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1654702119_add_mutual_contact_settings.up.sql", size: 78, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x26, 0x66, 0x67, 0x50, 0xfe, 0xd7, 0xe3, 0x29, 0x8b, 0xff, 0x9d, 0x5a, 0x87, 0xa7, 0x99, 0x6e, 0xd6, 0xcd, 0x2e, 0xbb, 0x17, 0xdf, 0x7f, 0xf7, 0xa3, 0xfa, 0x32, 0x7c, 0x2d, 0x92, 0xc8, 0x74}} return a, nil } @@ -545,7 +546,7 @@ func _1655375270_add_clock_field_to_communities_settings_tableUpSql() (*asset, e return nil, err } - info := bindataFileInfo{name: "1655375270_add_clock_field_to_communities_settings_table.up.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1655375270_add_clock_field_to_communities_settings_table.up.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x19, 0xc5, 0xc0, 0xf9, 0x84, 0x53, 0xdf, 0x83, 0xcf, 0xb6, 0x40, 0x6d, 0xf5, 0xdc, 0x77, 0x37, 0xb7, 0xe3, 0xa, 0x75, 0xe7, 0x6, 0x11, 0xca, 0x2b, 0x51, 0x92, 0xdd, 0x7d, 0xdb, 0xc3, 0xf5}} return a, nil } @@ -565,7 +566,7 @@ func _1655385721_drop_networks_configUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1655385721_drop_networks_config.up.sql", size: 27, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1655385721_drop_networks_config.up.sql", size: 27, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfc, 0xa7, 0x20, 0xbb, 0x67, 0x21, 0xe, 0xc6, 0xc8, 0x21, 0x74, 0xe0, 0xce, 0xc8, 0xe2, 0x2, 0xb4, 0xea, 0xf0, 0xe5, 0xc4, 0x4d, 0xdd, 0xd4, 0x52, 0x31, 0xa9, 0x3d, 0xcd, 0xd8, 0x9b, 0xab}} return a, nil } @@ -585,7 +586,7 @@ func _1655385724_networks_chaincolor_shortnameUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1655385724_networks_chainColor_shortName.up.sql", size: 220, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1655385724_networks_chainColor_shortName.up.sql", size: 220, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd9, 0xe7, 0x84, 0xbb, 0x5f, 0xd2, 0x2c, 0x42, 0x88, 0x62, 0x52, 0xb6, 0x58, 0x31, 0xac, 0xc, 0x96, 0x2b, 0x1b, 0xe5, 0x4e, 0x9a, 0x3a, 0xf6, 0xf6, 0xfc, 0xa9, 0x1a, 0x35, 0x62, 0x28, 0x88}} return a, nil } @@ -605,7 +606,7 @@ func _1655456688_add_deleted_at_field_to_bookmarks_tableUpSql() (*asset, error) return nil, err } - info := bindataFileInfo{name: "1655456688_add_deleted_at_field_to_bookmarks_table.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1655456688_add_deleted_at_field_to_bookmarks_table.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe7, 0x9a, 0xbd, 0x9a, 0xc9, 0xf, 0xdf, 0x90, 0x0, 0x5d, 0xea, 0x6e, 0x7d, 0x51, 0x95, 0xcd, 0x90, 0xd3, 0x1a, 0x36, 0x6c, 0xf4, 0xbd, 0xa7, 0x6b, 0xbf, 0xe5, 0xdb, 0xa3, 0x88, 0xe3, 0x50}} return a, nil } @@ -625,7 +626,7 @@ func _1655462032_create_bookmarks_deleted_at_indexUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1655462032_create_bookmarks_deleted_at_index.up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1655462032_create_bookmarks_deleted_at_index.up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf, 0x8e, 0x20, 0x6b, 0x14, 0x9e, 0xcd, 0x97, 0xd3, 0xfe, 0x62, 0x3, 0x26, 0x59, 0x1, 0x6c, 0x99, 0xef, 0x6d, 0x21, 0xd4, 0xb5, 0xa3, 0xf4, 0x39, 0x40, 0x54, 0x6, 0xd, 0x60, 0x13, 0x38}} return a, nil } @@ -645,7 +646,7 @@ func _1657617291_add_multi_transactions_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1657617291_add_multi_transactions_table.up.sql", size: 412, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1657617291_add_multi_transactions_table.up.sql", size: 412, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x86, 0xb0, 0x4e, 0x8c, 0x4, 0x82, 0xb4, 0x43, 0xaa, 0xd0, 0x16, 0xdd, 0xcb, 0x88, 0x81, 0xac, 0x4, 0x34, 0x1a, 0x8f, 0x2e, 0xc5, 0x69, 0xb, 0xf0, 0x17, 0xf7, 0xe3, 0x9, 0xe, 0x54, 0xe0}} return a, nil } @@ -665,7 +666,7 @@ func _1660134042_add_social_links_settings_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1660134042_add_social_links_settings_table.up.sql", size: 334, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1660134042_add_social_links_settings_table.up.sql", size: 334, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x84, 0x73, 0xb6, 0xe7, 0x3f, 0xaa, 0x39, 0x9a, 0x56, 0x56, 0x31, 0xf1, 0x8e, 0x26, 0x23, 0x1, 0xe4, 0xfa, 0x98, 0xfe, 0x78, 0x87, 0x20, 0xcb, 0x52, 0xf4, 0x38, 0x7f, 0xc4, 0x1c, 0x4, 0x22}} return a, nil } @@ -685,7 +686,7 @@ func _1660134060_settings_bioUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1660134060_settings_bio.up.sql", size: 91, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1660134060_settings_bio.up.sql", size: 91, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x46, 0x25, 0xa0, 0xa6, 0x47, 0xff, 0xbc, 0x2a, 0x0, 0xff, 0x59, 0x4b, 0xb0, 0xc9, 0x4e, 0x15, 0xe4, 0xd9, 0xda, 0xeb, 0xfe, 0x55, 0x98, 0xc3, 0x9d, 0x96, 0xe7, 0xf, 0xd1, 0x5c, 0x93, 0x73}} return a, nil } @@ -705,7 +706,7 @@ func _1660134070_add_wakuv2_storeUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1660134070_add_wakuv2_store.up.sql", size: 269, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1660134070_add_wakuv2_store.up.sql", size: 269, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1d, 0xe6, 0xc3, 0x9, 0xef, 0xdc, 0xae, 0x49, 0x30, 0x78, 0x54, 0xd6, 0xdb, 0xbf, 0xc0, 0x8e, 0x25, 0x8f, 0xfc, 0x67, 0x80, 0x39, 0x37, 0xd4, 0x86, 0xc1, 0x85, 0xc8, 0x99, 0xc4, 0x59, 0xd4}} return a, nil } @@ -725,7 +726,7 @@ func _1660134072_waku2_store_messagesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1660134072_waku2_store_messages.up.sql", size: 497, mode: os.FileMode(0644), modTime: time.Unix(1664364467, 0)} + info := bindataFileInfo{name: "1660134072_waku2_store_messages.up.sql", size: 497, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xeb, 0xb4, 0xa0, 0xa1, 0x2b, 0xcb, 0x4c, 0x3c, 0xc6, 0xd0, 0xe8, 0x96, 0xe3, 0x96, 0xf1, 0x4f, 0x1f, 0xe0, 0xe7, 0x1f, 0x85, 0xa3, 0xe, 0xf7, 0x52, 0x56, 0x63, 0x2b, 0xb0, 0x87, 0x7b}} return a, nil } @@ -745,7 +746,7 @@ func _1662365868_add_key_uid_accountsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1662365868_add_key_uid_accounts.up.sql", size: 68, mode: os.FileMode(0644), modTime: time.Unix(1668711465, 0)} + info := bindataFileInfo{name: "1662365868_add_key_uid_accounts.up.sql", size: 68, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc6, 0xd8, 0x2f, 0x2f, 0x3b, 0xa8, 0xbd, 0x6d, 0xf6, 0x87, 0x7e, 0xd2, 0xf1, 0xa2, 0xf7, 0x81, 0x6a, 0x23, 0x10, 0xbc, 0xbf, 0x5b, 0xe7, 0x2b, 0x9c, 0xa9, 0x8a, 0x18, 0xbb, 0xd0, 0x86, 0x91}} return a, nil } @@ -765,7 +766,7 @@ func _1662447680_add_keypairs_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1662447680_add_keypairs_table.up.sql", size: 218, mode: os.FileMode(0644), modTime: time.Unix(1668711465, 0)} + info := bindataFileInfo{name: "1662447680_add_keypairs_table.up.sql", size: 218, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdc, 0x25, 0xa9, 0xc7, 0x63, 0x27, 0x97, 0x35, 0x5f, 0x6b, 0xab, 0x26, 0xcb, 0xf9, 0xbd, 0x5e, 0xac, 0x3, 0xa0, 0x5e, 0xb9, 0x71, 0xa3, 0x1f, 0xb3, 0x4f, 0x7f, 0x79, 0x28, 0x48, 0xbe, 0xc}} return a, nil } @@ -785,7 +786,7 @@ func _1662460056_move_favourites_to_saved_addressesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1662460056_move_favourites_to_saved_addresses.up.sql", size: 233, mode: os.FileMode(0644), modTime: time.Unix(1668711465, 0)} + info := bindataFileInfo{name: "1662460056_move_favourites_to_saved_addresses.up.sql", size: 233, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x10, 0xa2, 0x8c, 0xa3, 0xec, 0xad, 0xdf, 0xc3, 0x48, 0x5, 0x9b, 0x50, 0x25, 0x59, 0xae, 0x7d, 0xee, 0x58, 0xd2, 0x41, 0x27, 0xf2, 0x22, 0x2e, 0x9a, 0xb9, 0x4a, 0xcc, 0x38, 0x6e, 0x3a, 0xb2}} return a, nil } @@ -805,7 +806,7 @@ func _1662738097_add_base_fee_transactionUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1662738097_add_base_fee_transaction.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1668711465, 0)} + info := bindataFileInfo{name: "1662738097_add_base_fee_transaction.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6b, 0xfb, 0x10, 0xae, 0xfc, 0x77, 0x70, 0x98, 0x6f, 0xec, 0xaa, 0xcd, 0x7, 0xc7, 0x74, 0x23, 0xc, 0xd5, 0x1e, 0x82, 0xdd, 0xfe, 0xff, 0x3b, 0xd2, 0x49, 0x10, 0x5b, 0x30, 0xc, 0x2d, 0xb0}} return a, nil } @@ -825,7 +826,7 @@ func _1662972194_add_keypairs_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1662972194_add_keypairs_table.up.sql", size: 345, mode: os.FileMode(0644), modTime: time.Unix(1668711465, 0)} + info := bindataFileInfo{name: "1662972194_add_keypairs_table.up.sql", size: 345, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xab, 0x76, 0xf2, 0x86, 0xe1, 0x7e, 0xe9, 0x47, 0x32, 0x48, 0xd5, 0x6b, 0xe5, 0xd, 0xab, 0xb7, 0xf1, 0xd4, 0xf1, 0xad, 0x38, 0xa6, 0x11, 0xe7, 0xce, 0x5c, 0x11, 0x11, 0xf, 0x47, 0xb2, 0x4}} return a, nil } @@ -845,7 +846,7 @@ func _1664392661_add_third_party_id_to_waku_messagesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1664392661_add_third_party_id_to_waku_messages.up.sql", size: 70, mode: os.FileMode(0644), modTime: time.Unix(1668711465, 0)} + info := bindataFileInfo{name: "1664392661_add_third_party_id_to_waku_messages.up.sql", size: 70, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfd, 0x67, 0x66, 0x9e, 0x66, 0x74, 0xce, 0x1c, 0xb, 0x1b, 0x9d, 0xd5, 0xfc, 0x65, 0xe, 0x83, 0x90, 0x4c, 0x61, 0x4e, 0x6b, 0xe7, 0x86, 0xbe, 0x36, 0x4f, 0x91, 0x36, 0x4, 0x47, 0x7b, 0x82}} return a, nil } @@ -865,7 +866,7 @@ func _1664783660_add_sync_info_to_saved_addressesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1664783660_add_sync_info_to_saved_addresses.up.sql", size: 388, mode: os.FileMode(0644), modTime: time.Unix(1668711465, 0)} + info := bindataFileInfo{name: "1664783660_add_sync_info_to_saved_addresses.up.sql", size: 388, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x67, 0x7c, 0x3a, 0x95, 0x4e, 0x55, 0xb2, 0xbd, 0xb4, 0x18, 0x93, 0xc1, 0xcf, 0x9f, 0x12, 0xbb, 0x49, 0x8a, 0x2a, 0x6a, 0x2a, 0x7f, 0xad, 0x44, 0xc3, 0xf, 0x3a, 0x79, 0x18, 0xb9, 0x4c, 0x64}} return a, nil } @@ -885,7 +886,7 @@ func _1668109917_wakunodesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1668109917_wakunodes.up.sql", size: 99, mode: os.FileMode(0644), modTime: time.Unix(1669031482, 0)} + info := bindataFileInfo{name: "1668109917_wakunodes.up.sql", size: 99, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x29, 0xaa, 0x9e, 0x2, 0x66, 0x85, 0x69, 0xa8, 0xd9, 0xe2, 0x4b, 0x8d, 0x2a, 0x9c, 0xdf, 0xd2, 0xef, 0x64, 0x58, 0xe3, 0xa6, 0xe7, 0xc1, 0xd1, 0xc8, 0x9c, 0xc0, 0x2c, 0x1, 0xa8, 0x7b, 0x81}} return a, nil } @@ -905,7 +906,7 @@ func _1670249678_display_name_to_settings_sync_clock_tableUpSql() (*asset, error return nil, err } - info := bindataFileInfo{name: "1670249678_display_name_to_settings_sync_clock_table.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1678711803, 0)} + info := bindataFileInfo{name: "1670249678_display_name_to_settings_sync_clock_table.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x39, 0x18, 0xdc, 0xc4, 0x1f, 0x79, 0x22, 0x16, 0x4d, 0xdf, 0x6c, 0x66, 0xd5, 0xa4, 0x88, 0x5d, 0x5, 0x37, 0xa7, 0x41, 0x5, 0x50, 0xae, 0x12, 0xfa, 0x7e, 0x89, 0x24, 0x5c, 0xae, 0x30, 0xfc}} return a, nil } @@ -925,7 +926,7 @@ func _1670836810_add_imported_flag_to_community_archive_hashesUpSql() (*asset, e return nil, err } - info := bindataFileInfo{name: "1670836810_add_imported_flag_to_community_archive_hashes.up.sql", size: 144, mode: os.FileMode(0644), modTime: time.Unix(1676035037, 0)} + info := bindataFileInfo{name: "1670836810_add_imported_flag_to_community_archive_hashes.up.sql", size: 144, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6f, 0xf, 0xf0, 0xbd, 0xfe, 0x63, 0x25, 0x8f, 0x5e, 0x46, 0x4b, 0x45, 0x31, 0x8b, 0x3e, 0xd8, 0x6b, 0x5d, 0x9d, 0x6d, 0x10, 0x9a, 0x87, 0x4b, 0x18, 0xc6, 0x39, 0x81, 0x6e, 0xe4, 0x75, 0xfb}} return a, nil } @@ -945,7 +946,7 @@ func _1671438731_add_magnetlink_uri_to_communities_archive_infoUpSql() (*asset, return nil, err } - info := bindataFileInfo{name: "1671438731_add_magnetlink_uri_to_communities_archive_info.up.sql", size: 86, mode: os.FileMode(0644), modTime: time.Unix(1678711803, 0)} + info := bindataFileInfo{name: "1671438731_add_magnetlink_uri_to_communities_archive_info.up.sql", size: 86, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xda, 0x8b, 0x4b, 0xd6, 0xd8, 0xe2, 0x3d, 0xf7, 0x6b, 0xcd, 0x1e, 0x70, 0x9, 0x2e, 0x35, 0x4, 0x61, 0xc3, 0xb5, 0x9d, 0xc5, 0x27, 0x21, 0xa, 0x5a, 0xd6, 0x3e, 0xa6, 0x24, 0xa2, 0x12, 0xdf}} return a, nil } @@ -965,7 +966,7 @@ func _1672933930_switcher_cardUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1672933930_switcher_card.up.sql", size: 162, mode: os.FileMode(0644), modTime: time.Unix(1678711803, 0)} + info := bindataFileInfo{name: "1672933930_switcher_card.up.sql", size: 162, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x39, 0xba, 0xdc, 0xbb, 0x40, 0x4, 0xf2, 0x10, 0xdf, 0xb4, 0xd2, 0x80, 0x8a, 0x74, 0x4d, 0xf6, 0xbc, 0x50, 0x7, 0xd, 0x22, 0x7f, 0xc4, 0xaf, 0xaa, 0xde, 0xdc, 0x71, 0xe9, 0x42, 0x98, 0x36}} return a, nil } @@ -985,7 +986,7 @@ func _1674056187_add_price_cacheUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1674056187_add_price_cache.up.sql", size: 255, mode: os.FileMode(0644), modTime: time.Unix(1678711803, 0)} + info := bindataFileInfo{name: "1674056187_add_price_cache.up.sql", size: 255, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb7, 0x79, 0x6a, 0x9b, 0x28, 0xd1, 0x22, 0xf0, 0x84, 0x76, 0x40, 0x39, 0x49, 0x15, 0x5d, 0xaa, 0xfd, 0x11, 0xff, 0x13, 0x27, 0x42, 0x12, 0xfa, 0x82, 0xe6, 0x7a, 0xf0, 0x5e, 0x1f, 0xe3, 0xba}} return a, nil } @@ -1005,7 +1006,7 @@ func _1674136690_ens_usernamesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1674136690_ens_usernames.up.sql", size: 98, mode: os.FileMode(0644), modTime: time.Unix(1678711803, 0)} + info := bindataFileInfo{name: "1674136690_ens_usernames.up.sql", size: 98, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x81, 0x7a, 0xf3, 0xa8, 0x88, 0x99, 0xd6, 0x9c, 0x69, 0x48, 0x3c, 0x10, 0xda, 0x72, 0xdc, 0x14, 0xd, 0x6e, 0x8c, 0x82, 0x92, 0x2d, 0x2c, 0xee, 0x4c, 0x70, 0xa4, 0xdc, 0x5c, 0x5, 0x2, 0xc3}} return a, nil } @@ -1025,7 +1026,7 @@ func _1674232431_add_balance_historyUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1674232431_add_balance_history.up.sql", size: 698, mode: os.FileMode(0644), modTime: time.Unix(1678711803, 0)} + info := bindataFileInfo{name: "1674232431_add_balance_history.up.sql", size: 698, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf7, 0xb5, 0x18, 0xca, 0x4a, 0x93, 0xbb, 0x6f, 0xa4, 0xee, 0xe4, 0x3e, 0xff, 0x6a, 0x4b, 0xe2, 0xe1, 0x61, 0x28, 0xee, 0xc5, 0x26, 0x57, 0x61, 0x5e, 0x6d, 0x44, 0x1e, 0x85, 0x43, 0x70, 0xa2}} return a, nil } @@ -1045,7 +1046,7 @@ func _1676368933_keypairs_to_keycardsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1676368933_keypairs_to_keycards.up.sql", size: 639, mode: os.FileMode(0644), modTime: time.Unix(1681203908, 0)} + info := bindataFileInfo{name: "1676368933_keypairs_to_keycards.up.sql", size: 639, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x81, 0x93, 0x27, 0x2, 0xf0, 0x37, 0x81, 0x65, 0xa4, 0xb3, 0x5b, 0x60, 0x36, 0x95, 0xfc, 0x81, 0xf0, 0x3b, 0x7c, 0xc3, 0x2c, 0x85, 0xbd, 0x38, 0x46, 0xa4, 0x95, 0x4a, 0x6, 0x3e, 0x74, 0xd5}} return a, nil } @@ -1065,7 +1066,7 @@ func _1676951398_add_currency_format_cacheUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1676951398_add_currency_format_cache.up.sql", size: 291, mode: os.FileMode(0644), modTime: time.Unix(1681203908, 0)} + info := bindataFileInfo{name: "1676951398_add_currency_format_cache.up.sql", size: 291, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf9, 0xa3, 0x76, 0x35, 0xca, 0xf, 0xe8, 0xdf, 0xd9, 0x61, 0xf9, 0xed, 0xfc, 0x6d, 0xf5, 0xe, 0x11, 0x88, 0xbd, 0x14, 0x92, 0xc6, 0x57, 0x53, 0xe, 0xcd, 0x52, 0xf4, 0xa9, 0xb1, 0xdd, 0xfd}} return a, nil } @@ -1085,7 +1086,7 @@ func _1676968196_keycards_add_clock_columnUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1676968196_keycards_add_clock_column.up.sql", size: 73, mode: os.FileMode(0644), modTime: time.Unix(1681203908, 0)} + info := bindataFileInfo{name: "1676968196_keycards_add_clock_column.up.sql", size: 73, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4c, 0xf, 0x1c, 0x28, 0x41, 0x57, 0x57, 0x6c, 0xe, 0x75, 0x6b, 0x75, 0x12, 0x0, 0x18, 0x1e, 0x88, 0x1e, 0x45, 0xe0, 0x32, 0xb9, 0xd4, 0xd9, 0x2e, 0xc8, 0xb, 0x80, 0x6, 0x51, 0x3d, 0x28}} return a, nil } @@ -1105,7 +1106,7 @@ func _1676968197_add_fallback_rpc_to_networksUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1676968197_add_fallback_rpc_to_networks.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1681203908, 0)} + info := bindataFileInfo{name: "1676968197_add_fallback_rpc_to_networks.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0x6a, 0xc6, 0x45, 0xfa, 0x62, 0x84, 0x74, 0x6d, 0x7c, 0xd7, 0x1d, 0x79, 0xb6, 0x38, 0x43, 0xa8, 0x8, 0x6b, 0x75, 0x3d, 0x9, 0x2, 0xc5, 0x9f, 0xbb, 0x45, 0x56, 0x4c, 0x4e, 0x17, 0x89}} return a, nil } @@ -1125,7 +1126,7 @@ func _1677674090_add_chains_ens_istest_to_saved_addressesUpSql() (*asset, error) return nil, err } - info := bindataFileInfo{name: "1677674090_add_chains_ens_istest_to_saved_addresses.up.sql", size: 638, mode: os.FileMode(0644), modTime: time.Unix(1681203908, 0)} + info := bindataFileInfo{name: "1677674090_add_chains_ens_istest_to_saved_addresses.up.sql", size: 638, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0x2d, 0xa4, 0x1b, 0xf6, 0x6a, 0x13, 0x7b, 0xe, 0x59, 0xcd, 0xe2, 0x4e, 0x81, 0x99, 0xc4, 0x33, 0x84, 0xde, 0x66, 0xca, 0xac, 0x2f, 0x5, 0x90, 0xac, 0xfd, 0x4e, 0xfc, 0x55, 0x44, 0xe5}} return a, nil } @@ -1145,7 +1146,7 @@ func _1677681143_accounts_table_type_column_updateUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1677681143_accounts_table_type_column_update.up.sql", size: 135, mode: os.FileMode(0644), modTime: time.Unix(1681203908, 0)} + info := bindataFileInfo{name: "1677681143_accounts_table_type_column_update.up.sql", size: 135, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0xc4, 0x6, 0x42, 0x50, 0x1d, 0xf4, 0x48, 0x55, 0xbc, 0xa2, 0x19, 0xdd, 0xad, 0xc8, 0xc, 0xa7, 0x30, 0xb6, 0xaf, 0xe, 0x2b, 0xaa, 0x2a, 0xa4, 0xe1, 0xb9, 0x41, 0x23, 0x66, 0xd3, 0x3}} return a, nil } @@ -1165,7 +1166,7 @@ func _1678264207_accounts_table_new_columns_addedUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1678264207_accounts_table_new_columns_added.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1682525187, 0)} + info := bindataFileInfo{name: "1678264207_accounts_table_new_columns_added.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xd4, 0xf3, 0x35, 0xef, 0x5c, 0x19, 0x3c, 0x15, 0x90, 0x60, 0xbd, 0x1f, 0x81, 0xf0, 0x86, 0x73, 0x89, 0xa0, 0x70, 0xf2, 0x46, 0xae, 0xea, 0xd0, 0xc6, 0x9e, 0x55, 0x4a, 0x54, 0x62, 0xbb}} return a, nil } @@ -1185,7 +1186,7 @@ func _1680770368_add_bio_to_settings_sync_clock_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1680770368_add_bio_to_settings_sync_clock_table.up.sql", size: 75, mode: os.FileMode(0644), modTime: time.Unix(1682525187, 0)} + info := bindataFileInfo{name: "1680770368_add_bio_to_settings_sync_clock_table.up.sql", size: 75, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4a, 0x52, 0xf6, 0x3f, 0xaa, 0xd, 0xa0, 0xee, 0xe8, 0xe6, 0x16, 0x21, 0x80, 0x61, 0xe4, 0x7a, 0x4e, 0x37, 0x8d, 0x30, 0x51, 0x20, 0x4d, 0x15, 0x47, 0xfb, 0x6, 0xa1, 0xce, 0xc8, 0x27, 0x5a}} return a, nil } @@ -1205,7 +1206,7 @@ func _1681110436_add_mnemonic_to_settings_sync_clock_tableUpSql() (*asset, error return nil, err } - info := bindataFileInfo{name: "1681110436_add_mnemonic_to_settings_sync_clock_table.up.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1682525187, 0)} + info := bindataFileInfo{name: "1681110436_add_mnemonic_to_settings_sync_clock_table.up.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3d, 0x74, 0x81, 0x7d, 0x9e, 0x77, 0xb6, 0xfe, 0xe3, 0xcb, 0x48, 0xe5, 0x5f, 0x39, 0x23, 0xa1, 0x7d, 0x53, 0x22, 0xe8, 0x96, 0x15, 0x8a, 0x1e, 0x8e, 0xbc, 0xe2, 0x1d, 0xc4, 0xc2, 0x56, 0x34}} return a, nil } @@ -1225,7 +1226,7 @@ func _1681392602_9d_sync_periodUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1681392602_9d_sync_period.up.sql", size: 60, mode: os.FileMode(0644), modTime: time.Unix(1682525187, 0)} + info := bindataFileInfo{name: "1681392602_9d_sync_period.up.sql", size: 60, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0xa, 0x90, 0x29, 0x7f, 0x76, 0x98, 0xa7, 0x71, 0x80, 0x5a, 0x2f, 0xbe, 0x23, 0x9a, 0xd4, 0xf4, 0x39, 0x19, 0xd3, 0xa5, 0x34, 0x6e, 0x67, 0x6a, 0xbe, 0x8a, 0xad, 0x21, 0xc7, 0xba, 0x88}} return a, nil } @@ -1245,7 +1246,7 @@ func _1681762078_default_sync_period_9dUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1681762078_default_sync_period_9d.up.sql", size: 3002, mode: os.FileMode(0644), modTime: time.Unix(1682525187, 0)} + info := bindataFileInfo{name: "1681762078_default_sync_period_9d.up.sql", size: 3002, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xd9, 0x26, 0xfc, 0xa9, 0x45, 0xc1, 0x81, 0xa8, 0xe2, 0x2c, 0xe9, 0x3c, 0xea, 0x1d, 0x37, 0x11, 0x45, 0x8c, 0x6c, 0xbc, 0xc2, 0x6, 0x69, 0x2, 0x75, 0x29, 0x40, 0x9f, 0xc5, 0xbb, 0x36}} return a, nil } @@ -1265,7 +1266,7 @@ func _1681780680_add_clock_to_social_links_settingsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1681780680_add_clock_to_social_links_settings.up.sql", size: 137, mode: os.FileMode(0644), modTime: time.Unix(1682525187, 0)} + info := bindataFileInfo{name: "1681780680_add_clock_to_social_links_settings.up.sql", size: 137, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x63, 0x11, 0xf5, 0x41, 0xe5, 0x5a, 0xf4, 0xe3, 0xf3, 0x14, 0x87, 0x28, 0xd8, 0xf0, 0x52, 0x31, 0x8, 0xd5, 0xbb, 0xf4, 0xff, 0x55, 0x5f, 0x42, 0x90, 0xcb, 0xf7, 0x46, 0x2, 0x6, 0xbe, 0x42}} return a, nil } @@ -1285,7 +1286,7 @@ func _1682073779_settings_table_remove_latest_derived_path_columnUpSql() (*asset return nil, err } - info := bindataFileInfo{name: "1682073779_settings_table_remove_latest_derived_path_column.up.sql", size: 4470, mode: os.FileMode(0644), modTime: time.Unix(1682525187, 0)} + info := bindataFileInfo{name: "1682073779_settings_table_remove_latest_derived_path_column.up.sql", size: 4470, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7a, 0x36, 0x2, 0x41, 0xd, 0x5c, 0xd1, 0x92, 0x85, 0x6d, 0x84, 0xff, 0x67, 0xa7, 0x4c, 0x67, 0xa4, 0xef, 0x52, 0x69, 0x1f, 0x22, 0x25, 0x92, 0xc, 0xb3, 0x89, 0x50, 0x91, 0xc, 0x49, 0xf9}} return a, nil } @@ -1305,7 +1306,7 @@ func _1682146075_add_created_at_to_saved_addressesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1682146075_add_created_at_to_saved_addresses.up.sql", size: 107, mode: os.FileMode(0644), modTime: time.Unix(1682525187, 0)} + info := bindataFileInfo{name: "1682146075_add_created_at_to_saved_addresses.up.sql", size: 107, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x88, 0xfe, 0x35, 0x9c, 0x6b, 0xdf, 0x67, 0x18, 0x16, 0xe4, 0xc9, 0xd4, 0x77, 0x7c, 0x4, 0xe2, 0x6c, 0x41, 0xd9, 0x53, 0x97, 0xfe, 0x5, 0xa3, 0x23, 0xce, 0x82, 0xad, 0x92, 0x5e, 0xd7, 0x7d}} return a, nil } @@ -1325,7 +1326,7 @@ func _1682393575_sync_ens_nameUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1682393575_sync_ens_name.up.sql", size: 713, mode: os.FileMode(0644), modTime: time.Unix(1683194402, 0)} + info := bindataFileInfo{name: "1682393575_sync_ens_name.up.sql", size: 713, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfb, 0xea, 0xcb, 0x4d, 0x71, 0x5a, 0x49, 0x19, 0x8b, 0xef, 0x66, 0x27, 0x33, 0x89, 0xb0, 0xe, 0x37, 0x1b, 0x41, 0x8, 0x12, 0xcc, 0x56, 0xd8, 0x1b, 0xf, 0xf8, 0x50, 0x4b, 0x93, 0xf1, 0x29}} return a, nil } @@ -1345,11 +1346,31 @@ func _1683457503_add_blocks_ranges_sequential_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1683457503_add_blocks_ranges_sequential_table.up.sql", size: 263, mode: os.FileMode(0644), modTime: time.Unix(1684503588, 0)} + info := bindataFileInfo{name: "1683457503_add_blocks_ranges_sequential_table.up.sql", size: 263, mode: os.FileMode(0644), modTime: time.Unix(1684513633, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfe, 0x57, 0x2e, 0x0, 0x6a, 0x6e, 0xd7, 0xeb, 0xe6, 0x66, 0x79, 0x32, 0x22, 0x82, 0x92, 0xf4, 0xc9, 0xf1, 0x58, 0x1a, 0x45, 0x60, 0x77, 0x50, 0xe7, 0x54, 0x4a, 0xc0, 0x42, 0x3a, 0x4f, 0x35}} return a, nil } +var __1683627613_accounts_and_keycards_improvementsUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x56\xcd\x72\xea\x36\x14\xde\xfb\x29\x4e\xd9\x94\xcc\x60\xee\x5d\x37\x93\xce\x38\x20\x6e\xe8\x25\x76\xc6\x38\x6d\xb3\x32\x8a\x75\x88\x55\x8c\xe4\xb1\x45\x12\xde\xbe\x23\xc9\x36\xc6\x38\x81\x66\x51\x36\xd8\x3a\x3f\xfa\xce\xdf\x77\xec\xba\xf0\x20\xcb\x92\x3f\x67\x08\x2b\x99\x63\x41\x9f\x33\x5c\x41\x22\xb3\xdd\x56\xc0\x2b\xcd\x76\x58\xfe\xe6\xb8\x2e\x0c\x84\x1c\x40\xf5\xfb\xf6\x0d\xa8\x00\x9a\x24\x72\x27\x14\xf0\x12\x84\x14\x50\x1b\x03\xaf\x8e\x14\x50\xd8\xe0\x3e\xa1\x05\x6b\x74\xa9\x60\xa0\x52\x2c\xd0\xaa\x68\x79\xa9\x64\x81\xb0\xe6\x19\xc2\x5a\x16\xda\x5a\x2b\xf5\xca\x54\x8a\x40\x19\x2b\xb0\x2c\xab\x5b\x18\x16\xfc\x15\x19\xac\x0b\xb9\x35\x28\x73\x5a\x28\x4e\xb3\x6c\x3f\x38\x45\xd9\xc8\x5a\x58\xd7\x97\xc3\x4d\x0a\xa4\x0a\xd9\xd7\x70\xad\x77\x06\x53\x6f\xf6\x8c\xec\x6b\x98\x68\x6f\x06\x1d\x7d\xa5\xc7\x18\x17\x2f\x20\xf0\x0d\x94\xf6\x5b\xc2\x6a\x83\xfb\x9c\xf2\xa2\x5c\x19\x27\xcd\x6b\x5c\xb9\x2e\x57\xce\x24\x24\x5e\x44\x20\xf2\x6e\x17\x04\xe6\x33\xf0\x83\x08\xc8\xdf\xf3\x65\xb4\x84\x5a\x1b\x86\x0e\xe8\x97\x78\xc7\x19\xfc\xe9\x85\x93\x3b\x2f\x84\x87\x70\x7e\xef\x85\x4f\xf0\x93\x3c\x19\x1b\xff\x71\xb1\x80\xc9\x1d\x99\xfc\x84\x61\x86\xe2\x45\xa5\x43\x55\xf0\xed\xb0\xb2\xbb\xba\x82\xdf\xe1\xfb\xd5\xc8\x01\x10\x74\x8b\x8d\x9b\xc6\x74\x4a\x66\xde\xe3\x22\x82\xc1\x40\xeb\xa8\x7d\x7e\x56\xa7\xca\x78\xac\x33\x7e\x4e\x37\xa3\xa5\x8a\x77\x25\xb2\xd8\x58\x51\xc5\xa5\x88\xb9\x60\xf8\x0e\x73\x3f\x3a\xb5\xfa\xae\x8d\xca\xbd\x48\x2e\xf1\x0f\xae\x0b\x1b\xc4\xbc\xd4\x55\xe6\x62\x2d\xe1\x2d\xe5\x49\x0a\x0c\x5f\x79\x82\xa0\x52\x5e\xd6\xb9\x34\x15\x64\xac\xee\x13\x80\x24\x93\xc9\xe6\x03\x0c\xce\xd5\xb5\x73\x49\x7d\x9a\x6a\x9a\x42\xd5\x6d\xd9\x53\xa8\xd1\x69\x1d\xf5\x51\xbe\x7b\xde\xe0\xfe\xe8\x84\xaa\xf4\x5c\x4a\x2f\x29\x63\x22\x33\x59\x9c\x53\xc2\xad\xfc\x87\x9f\x53\x7a\xa3\x59\x86\x0a\x6e\x83\x60\x71\xaa\x32\xf3\x16\x4b\x62\xee\x4b\xe9\x59\x9d\x94\x33\x86\xe2\x9c\x56\x33\x9b\x1f\xe3\x12\xd2\x96\x9e\x61\x99\x14\xfc\x19\xcb\xd6\x90\xff\x5a\x56\x1e\x78\xc6\xd5\x1e\x86\x05\x52\xa6\xc5\xf8\x9e\x67\x54\x98\xf6\x03\xaa\x0c\x8d\x28\x99\x83\x5c\xdb\x2e\xd1\x13\x7d\xa5\xe3\xb0\xc4\x13\x53\x05\x53\x2f\x22\xd1\xfc\x9e\x34\x00\x34\xba\x5d\xce\x3e\x95\x7f\xd6\x55\x5a\x3e\x0b\x42\x32\xff\xe1\xeb\x9e\x68\x06\x14\x42\x32\x23\x21\xf1\x27\xe4\xd0\x59\x07\xa1\xa3\x79\x2c\xf0\x61\x4a\x16\x24\x22\x30\xf1\x96\x13\x6f\x4a\x4c\x87\xba\x2e\xcc\x76\xd9\x9a\x67\x99\x66\x1f\x13\x92\x61\x1f\x67\xee\x2f\x49\x18\x69\x18\xc1\x81\x4b\x1c\x80\x25\x59\x90\x49\x54\x77\xe2\xa8\x96\xc5\xba\xa3\x46\x30\xc8\x0b\xa9\xf3\x30\x18\x1d\x4d\xf8\xe8\x93\x19\x1e\x99\x29\xb4\x41\xeb\xe8\xc2\xe0\x1e\x9a\x99\x70\x00\xfe\xba\x23\x21\xb1\x9c\xf2\xcb\x0d\x0c\xde\xa8\x4a\xd2\x01\x78\xfe\xf4\x70\x56\x22\xb2\xce\xd1\x06\xf7\x03\x07\xe0\x47\x18\x3c\x3e\xc0\xed\x53\x8d\xf7\xda\xf9\x62\x60\xda\xf1\xff\x1a\x53\xe7\xf5\x05\x05\x16\xba\x6d\xfe\x43\x54\x71\xfb\xca\x2a\x3c\x3a\xae\x28\x66\x04\x9b\x7c\xdc\x04\x4b\xc7\x96\x47\xcc\x13\x55\xa9\xfe\xb7\x81\xd3\xb1\xe1\x01\xfd\x60\x66\x5d\x3f\xd8\x79\x36\xb2\x94\x9a\x7f\x3b\x97\xa3\x7a\x71\x1a\x51\x33\x06\xfa\xed\xd0\xf4\x46\xd6\x9f\x19\xaa\x8f\x16\x64\x16\xc1\x1f\xc1\xdc\x3f\x54\x67\x93\x6b\x41\xe0\x03\xad\x11\xc3\x4d\x0b\xbe\x6d\xe3\x10\xb7\xf2\x55\x37\xb1\xcc\x18\xac\x9a\x1d\x69\xfb\xd9\x99\x86\xc1\x43\xc5\xc3\xb5\xe8\xba\xde\xbb\x7a\x0d\x23\x7f\x11\xfa\x42\x50\xd2\x6c\x5a\xbd\xc3\x1b\x63\xd7\x85\xa8\xf5\x15\x24\xf5\x3e\x87\x37\x6a\x94\xe9\x79\x7b\xc0\xf7\x04\x73\xa5\x45\x05\xba\x36\x2f\xd5\x98\x8d\x1d\x6f\x11\x91\xb0\x42\x56\xdb\x41\x48\x7c\xef\x9e\x80\xad\xa5\x39\x8a\x65\xc6\xae\x7b\x95\x0f\x55\xee\xb1\xaa\x65\xd6\xfc\xcc\x3e\xb2\x77\x0f\x0d\x5b\x54\xaf\x47\x5f\x0d\x0d\x1d\x75\xb6\xd2\x41\xbb\x77\xad\x1c\xab\xe8\xca\x23\x33\x0c\x4e\x3c\xff\x94\xbb\x4f\x3f\x56\x8e\xfd\xd8\xa1\x33\xdd\x14\x9f\x63\xca\x2f\x73\xe5\x47\x6c\x79\x41\xfe\x8e\xf7\xf9\xe7\x89\xb4\x18\x2b\x83\xb8\xbb\xfb\x8f\xb5\x3a\x91\xd4\x3e\xbb\xd1\x18\x0c\xc7\x0a\x87\x88\x1e\x1f\xf4\xc2\x69\x22\xfa\x2c\xd2\x0e\x9f\xd8\xd6\x68\xb1\x64\xa2\x3b\x6a\xdc\xba\x67\xd4\x3d\xb3\xf4\xd1\x39\xb4\xd5\x3f\xe6\x9e\x4a\xe5\xb4\xb0\x35\x3f\xb4\x67\xa0\xd2\x76\xe0\x23\x8a\x38\x5c\xd8\xc7\x13\x7d\x61\xf5\xd1\xe4\x26\x39\x89\x8d\x26\xd6\x73\xb7\x5c\x27\x28\xdb\x33\xd7\x32\x6c\x41\xb6\xd9\xdc\x24\x0d\xe2\xda\x77\xbb\x59\x6e\x3a\x20\xae\x9d\x36\x89\x7d\x30\xe1\x7d\x1a\x5a\xf0\x6f\x00\x00\x00\xff\xff\x42\x84\x7a\x0a\x38\x0e\x00\x00") + +func _1683627613_accounts_and_keycards_improvementsUpSqlBytes() ([]byte, error) { + return bindataRead( + __1683627613_accounts_and_keycards_improvementsUpSql, + "1683627613_accounts_and_keycards_improvements.up.sql", + ) +} + +func _1683627613_accounts_and_keycards_improvementsUpSql() (*asset, error) { + bytes, err := _1683627613_accounts_and_keycards_improvementsUpSqlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "1683627613_accounts_and_keycards_improvements.up.sql", size: 3640, mode: os.FileMode(0644), modTime: time.Unix(1684748654, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8e, 0xbe, 0x62, 0xf5, 0x9, 0x42, 0x8c, 0x8f, 0xa8, 0x45, 0xe7, 0x36, 0xc9, 0xde, 0xf4, 0xe2, 0xfd, 0xc4, 0x8, 0xd0, 0xa3, 0x8, 0x64, 0xe2, 0x56, 0xcc, 0xa7, 0x6d, 0xc5, 0xcc, 0x82, 0x2c}} + return a, nil +} + var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00") func docGoBytes() ([]byte, error) { @@ -1365,7 +1386,7 @@ func docGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1648117578, 0)} + info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1683916611, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x7c, 0x28, 0xcd, 0x47, 0xf2, 0xfa, 0x7c, 0x51, 0x2d, 0xd8, 0x38, 0xb, 0xb0, 0x34, 0x9d, 0x4c, 0x62, 0xa, 0x9e, 0x28, 0xc3, 0x31, 0x23, 0xd9, 0xbb, 0x89, 0x9f, 0xa0, 0x89, 0x1f, 0xe8}} return a, nil } @@ -1583,6 +1604,8 @@ var _bindata = map[string]func() (*asset, error){ "1683457503_add_blocks_ranges_sequential_table.up.sql": _1683457503_add_blocks_ranges_sequential_tableUpSql, + "1683627613_accounts_and_keycards_improvements.up.sql": _1683627613_accounts_and_keycards_improvementsUpSql, + "doc.go": docGo, } @@ -1688,6 +1711,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "1682146075_add_created_at_to_saved_addresses.up.sql": &bintree{_1682146075_add_created_at_to_saved_addressesUpSql, map[string]*bintree{}}, "1682393575_sync_ens_name.up.sql": &bintree{_1682393575_sync_ens_nameUpSql, map[string]*bintree{}}, "1683457503_add_blocks_ranges_sequential_table.up.sql": &bintree{_1683457503_add_blocks_ranges_sequential_tableUpSql, map[string]*bintree{}}, + "1683627613_accounts_and_keycards_improvements.up.sql": &bintree{_1683627613_accounts_and_keycards_improvementsUpSql, map[string]*bintree{}}, "doc.go": &bintree{docGo, map[string]*bintree{}}, }} diff --git a/appdatabase/migrations/sql/1683627613_accounts_and_keycards_improvements.up.sql b/appdatabase/migrations/sql/1683627613_accounts_and_keycards_improvements.up.sql new file mode 100644 index 000000000..08ba62794 --- /dev/null +++ b/appdatabase/migrations/sql/1683627613_accounts_and_keycards_improvements.up.sql @@ -0,0 +1,94 @@ +-- Possible `operable` column values: +-- "no" // an account is non operable it is not a keycard account and there is no keystore file for it and no keystore file for the address it is derived from +-- "partially" // an account is partially operable if it is not a keycard account and there is created keystore file for the address it is derived from +-- "fully" // an account is fully operable if it is not a keycard account and there is a keystore file for it + +-- Adding new tables `keypairs` and `keypairs_accounts` +CREATE TABLE IF NOT EXISTS keypairs ( + key_uid VARCHAR PRIMARY KEY NOT NULL CHECK (length(trim(key_uid)) > 0), + name VARCHAR NOT NULL DEFAULT "", + type VARCHAR NOT NULL DEFAULT "", + derived_from VARCHAR NOT NULL DEFAULT "", + last_used_derivation_index INT NOT NULL DEFAULT 0, + synced_from VARCHAR NOT NULL DEFAULT "", -- keeps an info which device this keypair is added from + clock INT NOT NULL DEFAULT 0 +); + +CREATE TABLE IF NOT EXISTS keypairs_accounts ( + address VARCHAR PRIMARY KEY, + key_uid VARCHAR, + pubkey VARCHAR, + path VARCHAR NOT NULL DEFAULT "", + name VARCHAR NOT NULL DEFAULT "", + color VARCHAR NOT NULL DEFAULT "", + emoji VARCHAR NOT NULL DEFAULT "", + wallet BOOL NOT NULL DEFAULT FALSE, + chat BOOL NOT NULL DEFAULT FALSE, + hidden BOOL NOT NULL DEFAULT FALSE, + operable VARCHAR NOT NULL DEFAULT "no", -- describes an account's operability (read an explanation at the top of this file) + created_at DATETIME NOT NULL, + updated_at DATETIME NOT NULL, + clock INT NOT NULL DEFAULT 0, + FOREIGN KEY(key_uid) REFERENCES keypairs(key_uid) + ON DELETE CASCADE +); + +-- Fulfilling the tables +INSERT INTO keypairs + SELECT key_uid, keypair_name, "profile", derived_from, last_used_derivation_index, "", clock + FROM accounts + WHERE type != "watch" AND type != "seed" AND type != "key" + GROUP BY key_uid; + +INSERT INTO keypairs + SELECT key_uid, keypair_name, type, derived_from, last_used_derivation_index, "", clock + FROM accounts + WHERE type != "watch" AND type != "" AND type != "generated" + GROUP BY key_uid; + +INSERT INTO keypairs_accounts + SELECT a.address, kp.key_uid, a.pubkey, a.path, a.name, a.color, a.emoji, a.wallet, a.chat, a.hidden, "fully", a.created_at, a.updated_at, a.clock + FROM accounts a + LEFT JOIN keypairs kp + ON a.key_uid = kp.key_uid; + +-- Removing old `accounts` table +DROP TABLE accounts; + +-- Add foreign key to `keycards` table +-- There is no other way to add foreign key to `keycards` table except to re-create tables. +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, + last_update_clock 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, + FOREIGN KEY(keycard_uid) REFERENCES keycards(keycard_uid) + ON UPDATE CASCADE + ON DELETE CASCADE +); + +INSERT INTO keycards + SELECT kc_old.keycard_uid, kc_old.keycard_name, kc_old.keycard_locked, kp.key_uid, kc_old.last_update_clock + FROM keycards_old kc_old + JOIN keypairs kp + ON kc_old.key_uid = kp.key_uid; + +INSERT INTO keycards_accounts + SELECT kc.keycard_uid, kc_acc_old.account_address + FROM keycards_accounts_old kc_acc_old + JOIN keycards kc + ON kc_acc_old.keycard_uid = kc.keycard_uid; + +DROP TABLE keycards_accounts_old; +DROP TABLE keycards_old; \ No newline at end of file diff --git a/multiaccounts/accounts/database.go b/multiaccounts/accounts/database.go index 2653ba599..cc05852b7 100644 --- a/multiaccounts/accounts/database.go +++ b/multiaccounts/accounts/database.go @@ -3,13 +3,12 @@ package accounts import ( "database/sql" "encoding/json" + "errors" "fmt" "strconv" "strings" "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/multiaccounts/errors" - "github.com/status-im/status-go/multiaccounts/keycards" "github.com/status-im/status-go/multiaccounts/settings" notificationssettings "github.com/status-im/status-go/multiaccounts/settings_notifications" sociallinkssettings "github.com/status-im/status-go/multiaccounts/settings_social_links" @@ -18,37 +17,70 @@ import ( ) const ( - uniqueChatConstraint = "UNIQUE constraint failed: accounts.chat" - uniqueWalletConstraint = "UNIQUE constraint failed: accounts.wallet" statusWalletRootPath = "m/44'/60'/0'/0/" + zeroAddress = "0x0000000000000000000000000000000000000000" + SyncedFromBackup = "backup" // means a account is coming from backed up data + SyncedFromLocalPairing = "local-pairing" // means a account is coming from another device when user is reocovering Status account ) -type Account struct { - Address types.Address `json:"address"` - KeyUID string `json:"key-uid"` - Wallet bool `json:"wallet"` - Chat bool `json:"chat"` - Type AccountType `json:"type,omitempty"` - Storage string `json:"storage,omitempty"` - Path string `json:"path,omitempty"` - PublicKey types.HexBytes `json:"public-key,omitempty"` - Name string `json:"name"` - Emoji string `json:"emoji"` - Color string `json:"color"` - Hidden bool `json:"hidden"` - DerivedFrom string `json:"derived-from,omitempty"` - Clock uint64 `json:"clock,omitempty"` - Removed bool `json:"removed,omitempty"` - KeypairName string `json:"keypair-name"` - LastUsedDerivationIndex uint64 `json:"last-used-derivation-index"` +var ( + errDbTransactionIsNil = errors.New("accounts: database transaction is nil") + ErrDbKeypairNotFound = errors.New("accounts: keypair is not found") + ErrDbAccountNotFound = errors.New("accounts: account is not found") + ErrKeypairDifferentAccountsKeyUID = errors.New("cannot store keypair with different accounts' key uid than keypair's key uid") + ErrKeypairWithoutAccounts = errors.New("cannot store keypair without accounts") +) + +type Keypair struct { + KeyUID string `json:"key-uid"` + Name string `json:"name"` + Type KeypairType `json:"type"` + DerivedFrom string `json:"derived-from"` + LastUsedDerivationIndex uint64 `json:"last-used-derivation-index,omitempty"` + SyncedFrom string `json:"synced-from,omitempty"` // keeps an info which device this keypair is added from can be one of two values defined in constants or device name (custom) + Clock uint64 `json:"clock,omitempty"` + Accounts []*Account `json:"accounts"` } +type Account struct { + Address types.Address `json:"address"` + KeyUID string `json:"key-uid"` + Wallet bool `json:"wallet"` + Chat bool `json:"chat"` + Type AccountType `json:"type,omitempty"` + Path string `json:"path,omitempty"` + PublicKey types.HexBytes `json:"public-key,omitempty"` + Name string `json:"name"` + Emoji string `json:"emoji"` + Color string `json:"color"` + Hidden bool `json:"hidden"` + Clock uint64 `json:"clock,omitempty"` + Removed bool `json:"removed,omitempty"` + Operable AccountOperable `json:"operable"` // describes an account's operability (read an explanation at the top of this file) +} + +type KeypairType string type AccountType string +type AccountOperable string + +func (a KeypairType) String() string { + return string(a) +} func (a AccountType) String() string { return string(a) } +func (a AccountOperable) String() string { + return string(a) +} + +const ( + KeypairTypeProfile KeypairType = "profile" + KeypairTypeKey KeypairType = "key" + KeypairTypeSeed KeypairType = "seed" +) + const ( AccountTypeGenerated AccountType = "generated" AccountTypeKey AccountType = "key" @@ -56,6 +88,12 @@ const ( AccountTypeWatch AccountType = "watch" ) +const ( + AccountNonOperable AccountOperable = "no" // an account is non operable it is not a keycard account and there is no keystore file for it and no keystore file for the address it is derived from + AccountPartiallyOperable AccountOperable = "partially" // an account is partially operable if it is not a keycard account and there is created keystore file for the address it is derived from + AccountFullyOperable AccountOperable = "fully" // an account is fully operable if it is not a keycard account and there is a keystore file for it +) + // IsOwnAccount returns true if this is an account we have the private key for // NOTE: Wallet flag can't be used as it actually indicates that it's the default // Wallet @@ -65,54 +103,106 @@ func (a *Account) IsOwnAccount() bool { func (a *Account) MarshalJSON() ([]byte, error) { item := struct { - Address types.Address `json:"address"` - MixedcaseAddress string `json:"mixedcase-address"` - KeyUID string `json:"key-uid"` - Wallet bool `json:"wallet"` - Chat bool `json:"chat"` - Type AccountType `json:"type,omitempty"` - Storage string `json:"storage,omitempty"` - Path string `json:"path,omitempty"` - PublicKey types.HexBytes `json:"public-key,omitempty"` - Name string `json:"name"` - Emoji string `json:"emoji"` - Color string `json:"color"` - Hidden bool `json:"hidden"` - DerivedFrom string `json:"derived-from,omitempty"` - Clock uint64 `json:"clock"` - Removed bool `json:"removed"` - KeypairName string `json:"keypair-name"` - LastUsedDerivationIndex uint64 `json:"last-used-derivation-index"` + Address types.Address `json:"address"` + MixedcaseAddress string `json:"mixedcase-address"` + KeyUID string `json:"key-uid"` + Wallet bool `json:"wallet"` + Chat bool `json:"chat"` + Type AccountType `json:"type"` + Path string `json:"path"` + PublicKey types.HexBytes `json:"public-key"` + Name string `json:"name"` + Emoji string `json:"emoji"` + Color string `json:"color"` + Hidden bool `json:"hidden"` + Clock uint64 `json:"clock"` + Removed bool `json:"removed"` + Operable AccountOperable `json:"operable"` }{ - Address: a.Address, - MixedcaseAddress: a.Address.Hex(), - KeyUID: a.KeyUID, - Wallet: a.Wallet, - Chat: a.Chat, - Type: a.Type, - Storage: a.Storage, - Path: a.Path, - PublicKey: a.PublicKey, - Name: a.Name, - Emoji: a.Emoji, - Color: a.Color, - Hidden: a.Hidden, - DerivedFrom: a.DerivedFrom, - Clock: a.Clock, - Removed: a.Removed, - KeypairName: a.KeypairName, - LastUsedDerivationIndex: a.LastUsedDerivationIndex, + Address: a.Address, + MixedcaseAddress: a.Address.Hex(), + KeyUID: a.KeyUID, + Wallet: a.Wallet, + Chat: a.Chat, + Type: a.Type, + Path: a.Path, + PublicKey: a.PublicKey, + Name: a.Name, + Emoji: a.Emoji, + Color: a.Color, + Hidden: a.Hidden, + Clock: a.Clock, + Removed: a.Removed, + Operable: a.Operable, } return json.Marshal(item) } +func (a *Keypair) MarshalJSON() ([]byte, error) { + item := struct { + KeyUID string `json:"key-uid"` + Name string `json:"name"` + Type KeypairType `json:"type"` + DerivedFrom string `json:"derived-from"` + LastUsedDerivationIndex uint64 `json:"last-used-derivation-index"` + SyncedFrom string `json:"synced-from"` + Clock uint64 `json:"clock"` + Accounts []*Account `json:"accounts"` + }{ + KeyUID: a.KeyUID, + Name: a.Name, + Type: a.Type, + DerivedFrom: a.DerivedFrom, + LastUsedDerivationIndex: a.LastUsedDerivationIndex, + SyncedFrom: a.SyncedFrom, + Clock: a.Clock, + Accounts: a.Accounts, + } + + return json.Marshal(item) +} + +func (a *Keypair) CopyKeypair() *Keypair { + kp := &Keypair{ + Clock: a.Clock, + KeyUID: a.KeyUID, + Name: a.Name, + Type: a.Type, + DerivedFrom: a.DerivedFrom, + LastUsedDerivationIndex: a.LastUsedDerivationIndex, + SyncedFrom: a.SyncedFrom, + Accounts: make([]*Account, len(a.Accounts)), + } + + for i, acc := range a.Accounts { + kp.Accounts[i] = &Account{ + Address: acc.Address, + KeyUID: acc.KeyUID, + Wallet: acc.Wallet, + Chat: acc.Chat, + Type: acc.Type, + Path: acc.Path, + PublicKey: acc.PublicKey, + Name: acc.Name, + Emoji: acc.Emoji, + Color: acc.Color, + Hidden: acc.Hidden, + Clock: acc.Clock, + Removed: acc.Removed, + Operable: acc.Operable, + } + } + + return kp +} + // Database sql wrapper for operations with browser objects. type Database struct { *settings.Database *notificationssettings.NotificationsSettings *sociallinkssettings.SocialLinksSettings - *keycards.Keycards + *Keycards db *sql.DB } @@ -124,14 +214,9 @@ func NewDB(db *sql.DB) (*Database, error) { } sn := notificationssettings.NewNotificationsSettings(db) ssl := sociallinkssettings.NewSocialLinksSettings(db) - kp := keycards.NewKeycards(db) + kc := NewKeycards(db) - err = updateKeypairNameAndLastDerivationIndexIfNeeded(db) - if err != nil { - return nil, err - } - - return &Database{sDB, sn, ssl, kp, db}, nil + return &Database{sDB, sn, ssl, kc, db}, nil } // DB Gets db sql.DB @@ -144,235 +229,542 @@ func (db *Database) Close() error { return db.db.Close() } -func updateKeypairNameAndLastUsedIndex(tx *sql.Tx, keyUID string, keypairName string, index uint64) (err error) { - if tx == nil { - return errors.ErrDbTransactionIsNil +func getAccountTypeForKeypairType(kpType KeypairType) AccountType { + switch kpType { + case KeypairTypeProfile: + return AccountTypeGenerated + case KeypairTypeKey: + return AccountTypeKey + case KeypairTypeSeed: + return AccountTypeSeed + default: + return AccountTypeWatch } - - _, err = tx.Exec(` - UPDATE - accounts - SET - keypair_name = ?, - last_used_derivation_index = ? - WHERE - key_uid = ? - AND - NOT chat`, - keypairName, index, keyUID) - - return err } -func updateKeypairNameAndLastDerivationIndexIfNeeded(db *sql.DB) error { - tx, err := db.Begin() - if err != nil { - return err - } - defer func() { - if err == nil { - err = tx.Commit() - return - } - _ = tx.Rollback() - }() - - var displayName string - err = tx.QueryRow("SELECT display_name FROM settings WHERE synthetic_id = 'id'").Scan(&displayName) - if err != nil && err != sql.ErrNoRows { - return err - } - - if displayName == "" { - displayName = "Status" - } +func (db *Database) processKeypairs(rows *sql.Rows) ([]*Keypair, error) { + keypairMap := make(map[string]*Keypair) var ( - seedKeyPairIndex int - keyKeyPairIndex int + kpKeyUID sql.NullString + kpName sql.NullString + kpType sql.NullString + kpDerivedFrom sql.NullString + kpLastUsedDerivationIndex sql.NullInt64 + kpSyncedFrom sql.NullString + kpClock sql.NullInt64 ) - for { - // Except for the Status chat account, keypair must not be empty and it must be unique per keypair. - rows, err := tx.Query(`SELECT wallet, type, path, derived_from, key_uid FROM accounts WHERE keypair_name = "" AND NOT chat ORDER BY key_uid`) - if err != nil { - if err == sql.ErrNoRows { - return nil - } - return err - } - defer rows.Close() + var ( + accAddress sql.NullString + accKeyUID sql.NullString + accPath sql.NullString + accName sql.NullString + accColor sql.NullString + accEmoji sql.NullString + accWallet sql.NullBool + accChat sql.NullBool + accHidden sql.NullBool + accOperable sql.NullString + accClock sql.NullInt64 + ) - var dbAccounts []*Account - for rows.Next() { - acc := &Account{} - err := rows.Scan(&acc.Wallet, &acc.Type, &acc.Path, &acc.DerivedFrom, &acc.KeyUID) - if err != nil { - return err - } - dbAccounts = append(dbAccounts, acc) - } - - if err = rows.Err(); err != nil { - return err - } - - resolveLastUsedIndex := func(keyUID string) uint64 { - lastUsedIndex := uint64(0) - for _, acc := range dbAccounts { - if acc.KeyUID == keyUID && strings.HasPrefix(acc.Path, statusWalletRootPath) { - index, err := strconv.ParseUint(acc.Path[len(statusWalletRootPath):], 0, 64) - if err != nil { - continue - } - if index > lastUsedIndex { - lastUsedIndex = index - } - } - } - return lastUsedIndex - } - - if len(dbAccounts) > 0 { - acc := dbAccounts[0] - keypairName := displayName - if acc.Type == AccountTypeSeed { - seedKeyPairIndex++ - keypairName = fmt.Sprintf(`Seed imported %d`, seedKeyPairIndex) - } else if acc.Type == AccountTypeKey { - keyKeyPairIndex++ - keypairName = fmt.Sprintf(`Key imported %d`, keyKeyPairIndex) - } - - err = updateKeypairNameAndLastUsedIndex(tx, acc.KeyUID, keypairName, resolveLastUsedIndex(acc.KeyUID)) - if err != nil { - return err - } - } else { - return nil - } - } -} - -func (db *Database) GetAccountsByKeyUID(keyUID string) ([]*Account, error) { - accounts, err := db.GetAccounts() - if err != nil { - return nil, err - } - filteredAccounts := make([]*Account, 0) - for _, account := range accounts { - if account.KeyUID == keyUID { - filteredAccounts = append(filteredAccounts, account) - } - } - return filteredAccounts, nil -} - -func (db *Database) GetAccounts() ([]*Account, error) { - rows, err := db.db.Query(` - SELECT - address, - wallet, - chat, - type, - storage, - pubkey, - path, - name, - emoji, - color, - hidden, - derived_from, - clock, - key_uid, - keypair_name, - last_used_derivation_index - FROM - accounts - ORDER BY - created_at`) - if err != nil { - return nil, err - } - defer rows.Close() - accounts := []*Account{} - pubkey := []byte{} for rows.Next() { + kp := &Keypair{} acc := &Account{} + pubkey := []byte{} err := rows.Scan( - &acc.Address, &acc.Wallet, &acc.Chat, &acc.Type, &acc.Storage, &pubkey, &acc.Path, &acc.Name, &acc.Emoji, - &acc.Color, &acc.Hidden, &acc.DerivedFrom, &acc.Clock, &acc.KeyUID, &acc.KeypairName, &acc.LastUsedDerivationIndex) + &kpKeyUID, &kpName, &kpType, &kpDerivedFrom, &kpLastUsedDerivationIndex, &kpSyncedFrom, &kpClock, + &accAddress, &accKeyUID, &pubkey, &accPath, &accName, &accColor, &accEmoji, + &accWallet, &accChat, &accHidden, &accOperable, &accClock) if err != nil { return nil, err } + + // check keypair fields + if kpKeyUID.Valid { + kp.KeyUID = kpKeyUID.String + } + if kpName.Valid { + kp.Name = kpName.String + } + if kpType.Valid { + kp.Type = KeypairType(kpType.String) + } + if kpDerivedFrom.Valid { + kp.DerivedFrom = kpDerivedFrom.String + } + if kpLastUsedDerivationIndex.Valid { + kp.LastUsedDerivationIndex = uint64(kpLastUsedDerivationIndex.Int64) + } + if kpSyncedFrom.Valid { + kp.SyncedFrom = kpSyncedFrom.String + } + if kpClock.Valid { + kp.Clock = uint64(kpClock.Int64) + } + + // check keypair accounts fields + if accAddress.Valid { + acc.Address = types.BytesToAddress([]byte(accAddress.String)) + } + if accKeyUID.Valid { + acc.KeyUID = accKeyUID.String + } + if accPath.Valid { + acc.Path = accPath.String + } + if accName.Valid { + acc.Name = accName.String + } + if accColor.Valid { + acc.Color = accColor.String + } + if accEmoji.Valid { + acc.Emoji = accEmoji.String + } + if accWallet.Valid { + acc.Wallet = accWallet.Bool + } + if accChat.Valid { + acc.Chat = accChat.Bool + } + if accHidden.Valid { + acc.Hidden = accHidden.Bool + } + if accOperable.Valid { + acc.Operable = AccountOperable(accOperable.String) + } + if accClock.Valid { + acc.Clock = uint64(accClock.Int64) + } + if lth := len(pubkey); lth > 0 { acc.PublicKey = make(types.HexBytes, lth) copy(acc.PublicKey, pubkey) } - accounts = append(accounts, acc) + acc.Type = getAccountTypeForKeypairType(kp.Type) + + if _, ok := keypairMap[kp.KeyUID]; !ok { + keypairMap[kp.KeyUID] = kp + } + keypairMap[kp.KeyUID].Accounts = append(keypairMap[kp.KeyUID].Accounts, acc) } - return accounts, nil + + if err := rows.Err(); err != nil { + return nil, err + } + + // Convert map to list + keypairs := make([]*Keypair, 0, len(keypairMap)) + for _, keypair := range keypairMap { + keypairs = append(keypairs, keypair) + } + + return keypairs, nil } -func (db *Database) GetAccountByAddress(address types.Address) (rst *Account, err error) { - row := db.db.QueryRow(` +// If `keyUID` is passed only keypairs which match the passed `keyUID` will be returned, if `keyUID` is empty, all keypairs will be returned. +func (db *Database) getKeypairs(tx *sql.Tx, keyUID string) ([]*Keypair, error) { + var ( + rows *sql.Rows + err error + where string + ) + if keyUID != "" { + where = "WHERE k.key_uid = ?" + } + query := fmt.Sprintf( // nolint: gosec + ` SELECT - address, - wallet, - chat, - type, - storage, - pubkey, - path, - name, - emoji, - color, - hidden, - derived_from, - clock, - key_uid, - keypair_name, - last_used_derivation_index + k.*, + ka.address, + ka.key_uid, + ka.pubkey, + ka.path, + ka.name, + ka.color, + ka.emoji, + ka.wallet, + ka.chat, + ka.hidden, + ka.operable, + ka.clock FROM - accounts - WHERE - address = ? COLLATE NOCASE`, - address) + keypairs k + LEFT JOIN + keypairs_accounts ka + ON + k.key_uid = ka.key_uid + %s + ORDER BY + ka.created_at`, where) - acc := &Account{} - pubkey := []byte{} - err = row.Scan( - &acc.Address, &acc.Wallet, &acc.Chat, &acc.Type, &acc.Storage, &pubkey, &acc.Path, &acc.Name, &acc.Emoji, - &acc.Color, &acc.Hidden, &acc.DerivedFrom, &acc.Clock, &acc.KeyUID, &acc.KeypairName, &acc.LastUsedDerivationIndex) + if tx == nil { + if where != "" { + rows, err = db.db.Query(query, keyUID) + } else { + rows, err = db.db.Query(query) + } + if err != nil { + return nil, err + } + } else { + stmt, err := tx.Prepare(query) + if err != nil { + return nil, err + } + defer stmt.Close() + if where != "" { + rows, err = stmt.Query(keyUID) + } else { + rows, err = stmt.Query() + } + if err != nil { + return nil, err + } + } + + defer rows.Close() + + return db.processKeypairs(rows) +} + +func (db *Database) getKeypairByKeyUID(tx *sql.Tx, keyUID string) (*Keypair, error) { + keypairs, err := db.getKeypairs(tx, keyUID) + if err != nil && err != sql.ErrNoRows { + return nil, err + } + + if len(keypairs) == 0 { + return nil, ErrDbKeypairNotFound + } + + return keypairs[0], nil +} + +// If `address` is passed only accounts which match the passed `address` will be returned, if `address` is empty, all accounts will be returned. +func (db *Database) getAccounts(tx *sql.Tx, address types.Address) ([]*Account, error) { + var ( + rows *sql.Rows + err error + where string + ) + if address.String() != zeroAddress { + where = "WHERE ka.address = ?" + } + + query := fmt.Sprintf( // nolint: gosec + ` + SELECT + k.*, + ka.address, + ka.key_uid, + ka.pubkey, + ka.path, + ka.name, + ka.color, + ka.emoji, + ka.wallet, + ka.chat, + ka.hidden, + ka.operable, + ka.clock + FROM + keypairs_accounts ka + LEFT JOIN + keypairs k + ON + ka.key_uid = k.key_uid + %s + ORDER BY + ka.created_at`, where) + + if tx == nil { + if where != "" { + rows, err = db.db.Query(query, address) + } else { + rows, err = db.db.Query(query) + } + if err != nil { + return nil, err + } + } else { + stmt, err := tx.Prepare(query) + if err != nil { + return nil, err + } + defer stmt.Close() + + if where != "" { + rows, err = stmt.Query(address) + } else { + rows, err = stmt.Query() + } + if err != nil { + return nil, err + } + } + + defer rows.Close() + + keypairs, err := db.processKeypairs(rows) if err != nil { return nil, err } - acc.PublicKey = pubkey - return acc, nil + + allAccounts := []*Account{} + for _, kp := range keypairs { + allAccounts = append(allAccounts, kp.Accounts...) + } + + return allAccounts, nil } -func (db *Database) SaveAccounts(accounts []*Account) (err error) { - // Once mobile app introduces keypair we should check for the "KeypairName" and "DerivedFrom" field and return error - // if those fields are missing. - // - // Note: - // - Status chat account doesn't have "KeypairName" and "DerivedFrom" fields set - // - default Status wallet account has "KeypairName" and "DerivedFrom" fields set - // - accounts generated from the Status wallet master key have "KeypairName" and "DerivedFrom" fields set - // - accounts added importing private key don't have "DerivedFrom" (they have "KeypairName") - // - accounts added importing seed phrase or generated from already imported seed phrase have "KeypairName" and "DerivedFrom" fields set - // - watch only accounts don't have "KeypairName" and "DerivedFrom" fields set +func (db *Database) getAccountByAddress(tx *sql.Tx, address types.Address) (*Account, error) { + accounts, err := db.getAccounts(tx, address) + if err != nil && err != sql.ErrNoRows { + return nil, err + } - var ( - tx *sql.Tx - insert *sql.Stmt - delete *sql.Stmt - update *sql.Stmt - ) - tx, err = db.db.Begin() + if len(accounts) == 0 { + return nil, ErrDbAccountNotFound + } + + return accounts[0], nil +} + +func (db *Database) deleteKeypair(tx *sql.Tx, keyUID string) error { + keypairs, err := db.getKeypairs(tx, keyUID) + if err != nil && err != sql.ErrNoRows { + return err + } + + if len(keypairs) == 0 { + return ErrDbKeypairNotFound + } + + query := ` + DELETE + FROM + keypairs + WHERE + key_uid = ? + ` + + if tx == nil { + _, err := db.db.Exec(query, keyUID) + return err + } + + stmt, err := tx.Prepare(query) if err != nil { - return + return err + } + defer stmt.Close() + + _, err = stmt.Exec(keyUID) + return err +} + +func (db *Database) GetKeypairs() ([]*Keypair, error) { + return db.getKeypairs(nil, "") +} + +func (db *Database) GetKeypairByKeyUID(keyUID string) (*Keypair, error) { + return db.getKeypairByKeyUID(nil, keyUID) +} + +func (db *Database) GetAccounts() ([]*Account, error) { + return db.getAccounts(nil, types.Address{}) +} + +func (db *Database) GetAccountByAddress(address types.Address) (*Account, error) { + return db.getAccountByAddress(nil, address) +} + +func (db *Database) GetWatchOnlyAccounts() (res []*Account, err error) { + accounts, err := db.getAccounts(nil, types.Address{}) + if err != nil { + return nil, err + } + for _, acc := range accounts { + if acc.Type == AccountTypeWatch { + res = append(res, acc) + } + } + return +} + +func (db *Database) IsAnyAccountPartalyOrFullyOperableForKeyUID(keyUID string) (bool, error) { + kp, err := db.getKeypairByKeyUID(nil, keyUID) + if err != nil { + return false, err + } + + for _, acc := range kp.Accounts { + if acc.Operable != AccountNonOperable { + return true, nil + } + } + return false, nil +} + +func (db *Database) DeleteKeypair(keyUID string) error { + return db.deleteKeypair(nil, keyUID) +} + +func (db *Database) DeleteAccount(address types.Address) error { + tx, err := db.db.Begin() + defer func() { + if err == nil { + err = tx.Commit() + return + } + _ = tx.Rollback() + }() + + if err != nil { + return err + } + + acc, err := db.getAccountByAddress(tx, address) + if err != nil { + return err + } + + kp, err := db.getKeypairByKeyUID(tx, acc.KeyUID) + if err != nil && err != ErrDbKeypairNotFound { + return err + } + + if kp != nil && len(kp.Accounts) == 1 && kp.Accounts[0].Address == address { + return db.deleteKeypair(tx, acc.KeyUID) + } + + delete, err := tx.Prepare(` + DELETE + FROM + keypairs_accounts + WHERE + address = ? + `) + if err != nil { + return err + } + defer delete.Close() + + _, err = delete.Exec(address) + + return err +} + +func updateKeypairLastUsedIndex(tx *sql.Tx, keyUID string, index uint64, clock uint64) error { + if tx == nil { + return errDbTransactionIsNil + } + _, err := tx.Exec(` + UPDATE + keypairs + SET + last_used_derivation_index = ?, + clock = ? + WHERE + key_uid = ?`, + index, clock, keyUID) + + return err +} + +func (db *Database) saveOrUpdateAccounts(tx *sql.Tx, accounts []*Account) (err error) { + if tx == nil { + return errDbTransactionIsNil + } + + for _, acc := range accounts { + var relatedKeypair *Keypair + // only watch only accounts have an empty `KeyUID` field + var keyUID *string + if acc.KeyUID != "" { + relatedKeypair, err = db.getKeypairByKeyUID(tx, acc.KeyUID) + if err != nil { + if err == sql.ErrNoRows { + // all accounts, except watch only accounts, must have a row in `keypairs` table with the same key uid + continue + } + return err + } + keyUID = &acc.KeyUID + } + + _, err = tx.Exec(` + INSERT OR IGNORE INTO + keypairs_accounts (address, key_uid, pubkey, path, wallet, chat, created_at, updated_at) + VALUES + (?, ?, ?, ?, ?, ?, datetime('now'), datetime('now')); + + UPDATE + keypairs_accounts + SET + name = ?, + color = ?, + emoji = ?, + hidden = ?, + operable = ?, + clock = ? + WHERE + address = ?; + `, + acc.Address, keyUID, acc.PublicKey, acc.Path, acc.Wallet, acc.Chat, + acc.Name, acc.Color, acc.Emoji, acc.Hidden, acc.Operable, acc.Clock, acc.Address) + if err != nil { + return err + } + + if strings.HasPrefix(acc.Path, statusWalletRootPath) { + accIndex, err := strconv.ParseUint(acc.Path[len(statusWalletRootPath):], 0, 64) + if err != nil { + return err + } + + accountsContainPath := func(accounts []*Account, path string) bool { + for _, acc := range accounts { + if acc.Path == path { + return true + } + } + return false + } + + expectedNewKeypairIndex := relatedKeypair.LastUsedDerivationIndex + for { + expectedNewKeypairIndex++ + if !accountsContainPath(relatedKeypair.Accounts, statusWalletRootPath+strconv.FormatUint(expectedNewKeypairIndex, 10)) { + break + } + } + + if accIndex == expectedNewKeypairIndex { + err = updateKeypairLastUsedIndex(tx, acc.KeyUID, accIndex, acc.Clock) + if err != nil { + return err + } + } + } + } + + return nil +} + +func (db *Database) SaveOrUpdateAccounts(accounts []*Account) error { + if len(accounts) == 0 { + return errors.New("no provided accounts to save/update") + } + + tx, err := db.db.Begin() + if err != nil { + return err } defer func() { if err == nil { @@ -382,87 +774,74 @@ func (db *Database) SaveAccounts(accounts []*Account) (err error) { _ = tx.Rollback() }() - // NOTE(dshulyak) replace all record values using address (primary key) - // can't use `insert or replace` because of the additional constraints (wallet and chat) - insert, err = tx.Prepare("INSERT OR IGNORE INTO accounts (address, created_at, updated_at) VALUES (?, datetime('now'), datetime('now'))") - if err != nil { - return err - } - delete, err = tx.Prepare("DELETE FROM accounts WHERE address = ?") - update, err = tx.Prepare(`UPDATE accounts - SET - wallet = ?, - chat = ?, - type = ?, - storage = ?, - pubkey = ?, - path = ?, - name = ?, - emoji = ?, - color = ?, - hidden = ?, - derived_from = ?, - key_uid = ?, - updated_at = datetime('now'), - clock = ?, - keypair_name = ?, - last_used_derivation_index = ? - WHERE - address = ?`) - if err != nil { - return err - } - for i := range accounts { - acc := accounts[i] - if acc.Removed { - _, err = delete.Exec(acc.Address) - if err != nil { - return - } - continue - } - - _, err = insert.Exec(acc.Address) - if err != nil { - return - } - _, err = update.Exec(acc.Wallet, acc.Chat, acc.Type, acc.Storage, acc.PublicKey, acc.Path, acc.Name, acc.Emoji, acc.Color, - acc.Hidden, acc.DerivedFrom, acc.KeyUID, acc.Clock, acc.KeypairName, acc.LastUsedDerivationIndex, acc.Address) - if err != nil { - switch err.Error() { - case uniqueChatConstraint: - err = errors.ErrChatNotUnique - case uniqueWalletConstraint: - err = errors.ErrWalletNotUnique - } - return - } - - err = updateKeypairNameAndLastUsedIndex(tx, acc.KeyUID, acc.KeypairName, acc.LastUsedDerivationIndex) - if err != nil { - return - } - } - - return + return db.saveOrUpdateAccounts(tx, accounts) } -func (db *Database) DeleteAccount(address types.Address) error { - _, err := db.db.Exec("DELETE FROM accounts WHERE address = ?", address) - return err +func (db *Database) SaveOrUpdateKeypair(keypair *Keypair) error { + tx, err := db.db.Begin() + if err != nil { + return err + } + defer func() { + if err == nil { + err = tx.Commit() + return + } + _ = tx.Rollback() + }() + + // If keypair is being saved, not updated, then it must be at least one account and all accounts must have the same key uid. + dbKeypair, err := db.getKeypairByKeyUID(tx, keypair.KeyUID) + if err != nil && err != ErrDbKeypairNotFound { + return err + } + if dbKeypair == nil { + if len(keypair.Accounts) == 0 { + return ErrKeypairWithoutAccounts + } + for _, acc := range keypair.Accounts { + if acc.KeyUID == "" || acc.KeyUID != keypair.KeyUID { + return ErrKeypairDifferentAccountsKeyUID + } + } + } + + _, err = tx.Exec(` + INSERT OR IGNORE INTO + keypairs (key_uid, type, derived_from) + VALUES + (?, ?, ?); + + UPDATE + keypairs + SET + name = ?, + last_used_derivation_index = ?, + synced_from = ?, + clock = ? + WHERE + key_uid = ?; + `, keypair.KeyUID, keypair.Type, keypair.DerivedFrom, + keypair.Name, keypair.LastUsedDerivationIndex, keypair.SyncedFrom, keypair.Clock, keypair.KeyUID) + if err != nil { + return err + } + + return db.saveOrUpdateAccounts(tx, keypair.Accounts) } func (db *Database) GetWalletAddress() (rst types.Address, err error) { - err = db.db.QueryRow("SELECT address FROM accounts WHERE wallet = 1").Scan(&rst) + err = db.db.QueryRow("SELECT address FROM keypairs_accounts WHERE wallet = 1").Scan(&rst) return } func (db *Database) GetWalletAddresses() (rst []types.Address, err error) { - rows, err := db.db.Query("SELECT address FROM accounts WHERE chat = 0 ORDER BY created_at") + rows, err := db.db.Query("SELECT address FROM keypairs_accounts WHERE chat = 0 ORDER BY created_at") if err != nil { return nil, err } defer rows.Close() + for rows.Next() { addr := types.Address{} err = rows.Scan(&addr) @@ -471,20 +850,26 @@ func (db *Database) GetWalletAddresses() (rst []types.Address, err error) { } rst = append(rst, addr) } + + if err := rows.Err(); err != nil { + return nil, err + } + return rst, nil } func (db *Database) GetChatAddress() (rst types.Address, err error) { - err = db.db.QueryRow("SELECT address FROM accounts WHERE chat = 1").Scan(&rst) + err = db.db.QueryRow("SELECT address FROM keypairs_accounts WHERE chat = 1").Scan(&rst) return } func (db *Database) GetAddresses() (rst []types.Address, err error) { - rows, err := db.db.Query("SELECT address FROM accounts ORDER BY created_at") + rows, err := db.db.Query("SELECT address FROM keypairs_accounts ORDER BY created_at") if err != nil { return nil, err } defer rows.Close() + for rows.Next() { addr := types.Address{} err = rows.Scan(&addr) @@ -493,21 +878,50 @@ func (db *Database) GetAddresses() (rst []types.Address, err error) { } rst = append(rst, addr) } + + if err := rows.Err(); err != nil { + return nil, err + } + return rst, nil } // 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 accounts WHERE address = ?)", address).Scan(&exists) + err = db.db.QueryRow("SELECT EXISTS (SELECT 1 FROM keypairs_accounts WHERE address = ?)", address).Scan(&exists) return exists, err } // GetPath returns true if account with given address was recently key and doesn't have a key yet func (db *Database) GetPath(address types.Address) (path string, err error) { - err = db.db.QueryRow("SELECT path FROM accounts WHERE address = ?", address).Scan(&path) + err = db.db.QueryRow("SELECT path FROM keypairs_accounts WHERE address = ?", address).Scan(&path) return path, err } func (db *Database) GetNodeConfig() (*params.NodeConfig, error) { return nodecfg.GetNodeConfigFromDB(db.db) } + +// this doesn't update clock +func (db *Database) UpdateAccountToFullyOperable(keyUID string, address types.Address) (err error) { + tx, err := db.db.Begin() + defer func() { + if err == nil { + err = tx.Commit() + return + } + _ = tx.Rollback() + }() + + if err != nil { + return err + } + + _, err = db.getAccountByAddress(tx, address) + if err != nil { + return err + } + + _, err = tx.Exec(`UPDATE keypairs_accounts SET operable = ? WHERE address = ?`, AccountFullyOperable, address) + return err +} diff --git a/multiaccounts/keycards/database.go b/multiaccounts/accounts/keycard_database.go similarity index 90% rename from multiaccounts/keycards/database.go rename to multiaccounts/accounts/keycard_database.go index 0a72bbfeb..0533fabf1 100644 --- a/multiaccounts/keycards/database.go +++ b/multiaccounts/accounts/keycard_database.go @@ -1,4 +1,4 @@ -package keycards +package accounts import ( "database/sql" @@ -10,7 +10,7 @@ import ( "github.com/status-im/status-go/protocol/protobuf" ) -var errDbTransactionIsNil = errors.New("keycard: database transaction is nil") +var errKeycardDbTransactionIsNil = errors.New("keycard: database transaction is nil") type Keycard struct { KeycardUID string `json:"keycard-uid"` @@ -175,6 +175,9 @@ func (kp *Keycards) GetKeycardByKeyUID(keyUID string) ([]*Keycard, error) { k.keycard_uid `, keyUID) if err != nil { + if err == sql.ErrNoRows { + return []*Keycard{}, nil + } return nil, err } @@ -198,7 +201,7 @@ func (kp *Keycards) startTransactionAndCheckIfNeedToProceed(kcUID string, clock func (kp *Keycards) setLastUpdateClock(tx *sql.Tx, kcUID string, clock uint64) (err error) { if tx == nil { - return errDbTransactionIsNil + return errKeycardDbTransactionIsNil } _, err = tx.Exec(` @@ -216,7 +219,7 @@ func (kp *Keycards) setLastUpdateClock(tx *sql.Tx, kcUID string, clock uint64) ( func (kp *Keycards) getAccountsForKeycard(tx *sql.Tx, kcUID string) ([]types.Address, error) { var accountAddresses []types.Address if tx == nil { - return accountAddresses, errDbTransactionIsNil + return accountAddresses, errKeycardDbTransactionIsNil } rows, err := tx.Query(`SELECT account_address FROM keycards_accounts WHERE keycard_uid = ?`, kcUID) @@ -239,7 +242,7 @@ func (kp *Keycards) getAccountsForKeycard(tx *sql.Tx, kcUID string) ([]types.Add func (kp *Keycards) addAccounts(tx *sql.Tx, kcUID string, accountsAddresses []types.Address) (err error) { if tx == nil { - return errDbTransactionIsNil + return errKeycardDbTransactionIsNil } insertKcAcc, err := tx.Prepare(` @@ -272,7 +275,7 @@ func (kp *Keycards) addAccounts(tx *sql.Tx, kcUID string, accountsAddresses []ty func (kp *Keycards) deleteKeycard(tx *sql.Tx, kcUID string) (err error) { if tx == nil { - return errDbTransactionIsNil + return errKeycardDbTransactionIsNil } delete, err := tx.Prepare(` @@ -339,7 +342,7 @@ func (kp *Keycards) AddKeycardOrAddAccountsIfKeycardIsAdded(keycard Keycard) (ad return false, false, err } -func (kp *Keycards) SyncKeycards(syncingClock uint64, keycardsToSync []*Keycard) (err error) { +func (kp *Keycards) ApplyKeycardsForKeypairWithKeyUID(keyUID string, keycardsToSync []*Keycard) (err error) { tx, err := kp.db.Begin() if err != nil { return @@ -352,7 +355,7 @@ func (kp *Keycards) SyncKeycards(syncingClock uint64, keycardsToSync []*Keycard) _ = tx.Rollback() }() - rows, err := tx.Query(`SELECT * FROM keycards`) + rows, err := tx.Query(`SELECT * FROM keycards WHERE key_uid = ?`, keyUID) if err != nil && err != sql.ErrNoRows { return err } @@ -371,55 +374,54 @@ func (kp *Keycards) SyncKeycards(syncingClock uint64, keycardsToSync []*Keycard) } // apply those from `keycardsToSync` which are newer - for _, syncKp := range keycardsToSync { + for _, syncKc := range keycardsToSync { foundAtIndex := -1 for i := range dbKeycards { - if dbKeycards[i].KeycardUID == syncKp.KeycardUID { + if dbKeycards[i].KeycardUID == syncKc.KeycardUID { foundAtIndex = i break } } - doInsertOrReplace := true if foundAtIndex > -1 { - if dbKeycards[foundAtIndex].LastUpdateClock > syncKp.LastUpdateClock { - doInsertOrReplace = false - } + dbClock := dbKeycards[foundAtIndex].LastUpdateClock dbKeycards = removeElementAtIndex(dbKeycards, foundAtIndex) + + if dbClock > syncKc.LastUpdateClock { + continue + } + err = kp.deleteKeycard(tx, syncKc.KeycardUID) + if err != nil { + return err + } } - if doInsertOrReplace { - _, err = tx.Exec(` - INSERT OR REPLACE INTO - keycards - ( - keycard_uid, - keycard_name, - keycard_locked, - key_uid, - last_update_clock - ) - VALUES - (?, ?, ?, ?, ?);`, - syncKp.KeycardUID, syncKp.KeycardName, syncKp.KeycardLocked, syncKp.KeyUID, syncKp.LastUpdateClock) + _, 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 - } + if err != nil { + return err + } - err = kp.addAccounts(tx, syncKp.KeycardUID, syncKp.AccountsAddresses) - 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` and if they are older than the moment `keycardsToSync` was created at + // remove those from the db if they are not in `keycardsToSync` for _, dbKp := range dbKeycards { - if dbKp.LastUpdateClock > syncingClock { - continue - } - err = kp.deleteKeycard(tx, dbKp.KeycardUID) if err != nil { return err diff --git a/protocol/messenger.go b/protocol/messenger.go index 9a1e1d427..f57a5954c 100644 --- a/protocol/messenger.go +++ b/protocol/messenger.go @@ -2330,6 +2330,7 @@ func (m *Messenger) syncProfilePictures(rawMessageHandler RawMessageHandler) err // SyncDevices sends all public chats and contacts to paired devices // TODO remove use of photoPath in contacts func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string, rawMessageHandler RawMessageHandler) (err error) { + syncedFromLocalPairing := rawMessageHandler != nil if rawMessageHandler == nil { rawMessageHandler = m.dispatchMessage } @@ -2448,11 +2449,6 @@ func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string, return err } - accounts, err := m.settings.GetAccounts() - if err != nil { - return err - } - ids, err := m.persistence.LatestContactRequestIDs() if err != nil { @@ -2469,11 +2465,33 @@ func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string, } } - err = m.syncWallets(accounts, rawMessageHandler) + keypairs, err := m.settings.GetKeypairs() if err != nil { return err } + for _, kp := range keypairs { + if syncedFromLocalPairing { + kp.SyncedFrom = accounts.SyncedFromLocalPairing + } + err = m.syncKeypair(kp, true, rawMessageHandler) + if err != nil { + return err + } + } + + woAccounts, err := m.settings.GetWatchOnlyAccounts() + if err != nil { + return err + } + + for _, woAcc := range woAccounts { + err = m.syncWalletAccount(woAcc, rawMessageHandler) + if err != nil { + return err + } + } + savedAddresses, err := m.savedAddressesManager.GetRawSavedAddresses() if err != nil { return err @@ -2488,11 +2506,6 @@ func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string, } } - err = m.syncAllKeycards(ctx, rawMessageHandler) - if err != nil { - return err - } - if err = m.syncEnsUsernameDetails(ctx, rawMessageHandler); err != nil { return err } @@ -4198,18 +4211,48 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte } messageState.Response.AnonymousMetrics = append(messageState.Response.AnonymousMetrics, ams...) - case protobuf.SyncWalletAccounts: + case protobuf.SyncKeypair: if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) { logger.Warn("not coming from us, ignoring") continue } - p := msg.ParsedMessage.Interface().(protobuf.SyncWalletAccounts) + p := msg.ParsedMessage.Interface().(protobuf.SyncKeypair) m.outputToCSV(msg.TransportMessage.Timestamp, msg.ID, senderID, filter.Topic, filter.ChatID, msg.Type, p) - logger.Debug("Handling SyncWalletAccount", zap.Any("message", p)) - err = m.HandleSyncWalletAccount(messageState, p) + logger.Debug("Handling SyncKeypair", zap.Any("message", p)) + err = m.HandleSyncKeypair(messageState, p) if err != nil { - logger.Warn("failed to handle SyncWalletAccount", zap.Error(err)) + logger.Warn("failed to handle SyncKeypair", zap.Error(err)) + allMessagesProcessed = false + continue + } + case protobuf.SyncKeypairFull: + if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) { + logger.Warn("not coming from us, ignoring") + continue + } + + p := msg.ParsedMessage.Interface().(protobuf.SyncKeypairFull) + m.outputToCSV(msg.TransportMessage.Timestamp, msg.ID, senderID, filter.Topic, filter.ChatID, msg.Type, p) + logger.Debug("Handling SyncKeypairFull", zap.Any("message", p)) + err = m.HandleSyncKeypairFull(messageState, p) + if err != nil { + logger.Warn("failed to handle SyncKeypairFull", zap.Error(err)) + allMessagesProcessed = false + continue + } + case protobuf.SyncAccount: + if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) { + logger.Warn("not coming from us, ignoring") + continue + } + + p := msg.ParsedMessage.Interface().(protobuf.SyncAccount) + m.outputToCSV(msg.TransportMessage.Timestamp, msg.ID, senderID, filter.Topic, filter.ChatID, msg.Type, p) + logger.Debug("Handling SyncAccount", zap.Any("message", p)) + err = m.HandleSyncWalletAccount(messageState, p, "") + if err != nil { + logger.Warn("failed to handle SyncAccount", zap.Error(err)) allMessagesProcessed = false continue } @@ -4235,20 +4278,6 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte allMessagesProcessed = false continue } - case protobuf.SyncAllKeycards: - if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) { - logger.Warn("not coming from us, ignoring") - continue - } - - p := msg.ParsedMessage.Interface().(protobuf.SyncAllKeycards) - m.outputToCSV(msg.TransportMessage.Timestamp, msg.ID, senderID, filter.Topic, filter.ChatID, msg.Type, p) - err = m.handleSyncKeycards(messageState, p) - if err != nil { - logger.Warn("failed to handle SyncAllKeycards", zap.Error(err)) - allMessagesProcessed = false - continue - } case protobuf.SyncKeycardAction: if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) { logger.Warn("not coming from us, ignoring") diff --git a/protocol/messenger_backup.go b/protocol/messenger_backup.go index a463829c6..308310a6e 100644 --- a/protocol/messenger_backup.go +++ b/protocol/messenger_backup.go @@ -7,6 +7,7 @@ import ( "github.com/golang/protobuf/proto" "go.uber.org/zap" + "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/protobuf" @@ -95,12 +96,12 @@ func (m *Messenger) BackupData(ctx context.Context) (uint64, error) { return 0, errors[0] } - syncWalletAccounts, err := m.backupWalletAccounts() + fullKeypairsToBackup, err := m.backupKeypairs() if err != nil { return 0, err } - keycardsToBackup, err := m.prepareSyncAllKeycardsMessage(clock) + woAccountsToBackup, err := m.backupWatchOnlyAccounts() if err != nil { return 0, err } @@ -124,13 +125,13 @@ func (m *Messenger) BackupData(ctx context.Context) (uint64, error) { DataNumber: uint32(0), TotalNumber: uint32(len(settings)), }, - WalletAccountsDetails: &protobuf.FetchingBackedUpDataDetails{ + FullKeypairDetails: &protobuf.FetchingBackedUpDataDetails{ DataNumber: uint32(0), - TotalNumber: uint32(len(syncWalletAccounts.Accounts)), + TotalNumber: uint32(len(fullKeypairsToBackup)), }, - KeycardsDetails: &protobuf.FetchingBackedUpDataDetails{ + WatchOnlyAccountDetails: &protobuf.FetchingBackedUpDataDetails{ DataNumber: uint32(0), - TotalNumber: uint32(1), + TotalNumber: uint32(len(woAccountsToBackup)), }, } } @@ -179,24 +180,26 @@ func (m *Messenger) BackupData(ctx context.Context) (uint64, error) { } } - // Update wallet accounts messages encode and dispatch - for i, d := range syncWalletAccounts.Accounts { + // Update keypairs messages encode and dispatch + for i, d := range fullKeypairsToBackup { pb := backupDetailsOnly() - pb.WalletAccountsDetails.DataNumber = uint32(i + 1) - pb.WalletAccount = d + pb.FullKeypairDetails.DataNumber = uint32(i + 1) + pb.FullKeypair = d.FullKeypair err = m.encodeAndDispatchBackupMessage(ctx, pb, chat.ID) if err != nil { return 0, err } } - // Update keycards message encode and dispatch - pb := backupDetailsOnly() - pb.KeycardsDetails.DataNumber = 1 - pb.Keycards = &keycardsToBackup - err = m.encodeAndDispatchBackupMessage(ctx, pb, chat.ID) - if err != nil { - return 0, err + // Update watch only messages encode and dispatch + for i, d := range woAccountsToBackup { + pb := backupDetailsOnly() + pb.WatchOnlyAccountDetails.DataNumber = uint32(i + 1) + pb.WatchOnlyAccount = d.WatchOnlyAccount + err = m.encodeAndDispatchBackupMessage(ctx, pb, chat.ID) + if err != nil { + return 0, err + } } chat.LastClockValue = clock @@ -415,11 +418,45 @@ func (m *Messenger) backupProfile(ctx context.Context, clock uint64) ([]*protobu return backupMessages, nil } -func (m *Messenger) backupWalletAccounts() (*protobuf.SyncWalletAccounts, error) { - accounts, err := m.settings.GetAccounts() +func (m *Messenger) backupKeypairs() ([]*protobuf.Backup, error) { + keypairs, err := m.settings.GetKeypairs() if err != nil { return nil, err } - return m.prepareSyncWalletAccountsMessage(accounts), nil + var backupMessages []*protobuf.Backup + for _, kp := range keypairs { + + kp.SyncedFrom = accounts.SyncedFromBackup + fullKeypair, err := m.prepareSyncKeypairFullMessage(kp) + if err != nil { + return nil, err + } + + backupMessage := &protobuf.Backup{ + FullKeypair: fullKeypair, + } + + backupMessages = append(backupMessages, backupMessage) + } + + return backupMessages, nil +} + +func (m *Messenger) backupWatchOnlyAccounts() ([]*protobuf.Backup, error) { + accounts, err := m.settings.GetWatchOnlyAccounts() + if err != nil { + return nil, err + } + + var backupMessages []*protobuf.Backup + for _, acc := range accounts { + + backupMessage := &protobuf.Backup{} + backupMessage.WatchOnlyAccount = m.prepareSyncAccountMessage(acc) + + backupMessages = append(backupMessages, backupMessage) + } + + return backupMessages, nil } diff --git a/protocol/messenger_backup_handler.go b/protocol/messenger_backup_handler.go index 5fe70d66d..74c50b055 100644 --- a/protocol/messenger_backup_handler.go +++ b/protocol/messenger_backup_handler.go @@ -3,6 +3,7 @@ package protocol import ( "database/sql" + "github.com/status-im/status-go/multiaccounts/accounts" ensservice "github.com/status-im/status-go/services/ens" "github.com/status-im/status-go/protocol/identity" @@ -15,11 +16,12 @@ import ( ) const ( - SyncWakuSectionKeyProfile = "profile" - SyncWakuSectionKeyContacts = "contacts" - SyncWakuSectionKeyCommunities = "communities" - SyncWakuSectionKeySettings = "settings" - SyncWakuSectionKeyKeycards = "keycards" + SyncWakuSectionKeyProfile = "profile" + SyncWakuSectionKeyContacts = "contacts" + SyncWakuSectionKeyCommunities = "communities" + SyncWakuSectionKeySettings = "settings" + SyncWakuSectionKeyKeypairs = "keypairs" + SyncWakuSectionKeyWatchOnlyAccounts = "watchOnlyAccounts" ) func (m *Messenger) HandleBackup(state *ReceivedMessageState, message protobuf.Backup) []error { @@ -48,25 +50,28 @@ func (m *Messenger) HandleBackup(state *ReceivedMessageState, message protobuf.B errors = append(errors, err) } - err = m.handleBackedUpWalletAccount(message.WalletAccount) + err = m.handleFullKeypair(message.FullKeypair) if err != nil { errors = append(errors, err) } - err = m.handleBackedUpKeycards(message.Keycards) + err = m.handleWatchOnlyAccount(message.WatchOnlyAccount) if err != nil { errors = append(errors, err) } // Send signal about applied backup progress if m.config.messengerSignalsHandler != nil { - response := wakusync.WakuBackedUpDataResponse{} + response := wakusync.WakuBackedUpDataResponse{ + Clock: message.Clock, + } response.AddFetchingBackedUpDataDetails(SyncWakuSectionKeyProfile, message.ProfileDetails) response.AddFetchingBackedUpDataDetails(SyncWakuSectionKeyContacts, message.ContactsDetails) response.AddFetchingBackedUpDataDetails(SyncWakuSectionKeyCommunities, message.CommunitiesDetails) response.AddFetchingBackedUpDataDetails(SyncWakuSectionKeySettings, message.SettingsDetails) - response.AddFetchingBackedUpDataDetails(SyncWakuSectionKeyKeycards, message.KeycardsDetails) + response.AddFetchingBackedUpDataDetails(SyncWakuSectionKeyKeypairs, message.FullKeypairDetails) + response.AddFetchingBackedUpDataDetails(SyncWakuSectionKeyWatchOnlyAccounts, message.WatchOnlyAccountDetails) m.config.messengerSignalsHandler.SendWakuFetchingBackupProgress(&response) } @@ -196,43 +201,49 @@ func (m *Messenger) handleBackedUpSettings(message *protobuf.SyncSetting) error return nil } -func (m *Messenger) handleBackedUpKeycards(message *protobuf.SyncAllKeycards) error { +func (m *Messenger) handleFullKeypair(message *protobuf.SyncKeypairFull) error { if message == nil { return nil } - allKeycards, err := m.syncReceivedKeycards(*message) + keypair, keycards, err := m.handleSyncKeypairFull(message) + if err != nil { + return err + } + + if m.config.messengerSignalsHandler != nil { + kpResponse := wakusync.WakuBackedUpDataResponse{ + Keypair: keypair.CopyKeypair(), + } + + m.config.messengerSignalsHandler.SendWakuBackedUpKeypair(&kpResponse) + + kcResponse := wakusync.WakuBackedUpDataResponse{ + Keycards: keycards, + } + + m.config.messengerSignalsHandler.SendWakuBackedUpKeycards(&kcResponse) + } + + return nil +} + +func (m *Messenger) handleWatchOnlyAccount(message *protobuf.SyncAccount) error { + if message == nil { + return nil + } + + acc, err := m.handleSyncWalletAccount(message, accounts.SyncedFromBackup) if err != nil { return err } if m.config.messengerSignalsHandler != nil { response := wakusync.WakuBackedUpDataResponse{ - Keycards: allKeycards, + WatchOnlyAccount: acc, } - m.config.messengerSignalsHandler.SendWakuBackedUpKeycards(&response) - } - - return nil -} - -func (m *Messenger) handleBackedUpWalletAccount(message *protobuf.SyncWalletAccount) error { - if message == nil { - return nil - } - - acc, err := m.handleSyncWalletAccount(message) - if err != nil { - return err - } - - if m.config.messengerSignalsHandler != nil { - response := wakusync.WakuBackedUpDataResponse{ - WalletAccount: acc, - } - - m.config.messengerSignalsHandler.SendWakuBackedUpWalletAccount(&response) + m.config.messengerSignalsHandler.SendWakuBackedUpWatchOnlyAccount(&response) } return nil diff --git a/protocol/messenger_config.go b/protocol/messenger_config.go index 13de81746..f4b830503 100644 --- a/protocol/messenger_config.go +++ b/protocol/messenger_config.go @@ -57,8 +57,9 @@ type MessengerSignalsHandler interface { SendWakuFetchingBackupProgress(response *wakusync.WakuBackedUpDataResponse) SendWakuBackedUpProfile(response *wakusync.WakuBackedUpDataResponse) SendWakuBackedUpSettings(response *wakusync.WakuBackedUpDataResponse) - SendWakuBackedUpWalletAccount(response *wakusync.WakuBackedUpDataResponse) + SendWakuBackedUpKeypair(response *wakusync.WakuBackedUpDataResponse) SendWakuBackedUpKeycards(response *wakusync.WakuBackedUpDataResponse) + SendWakuBackedUpWatchOnlyAccount(response *wakusync.WakuBackedUpDataResponse) } type config struct { diff --git a/protocol/messenger_handler.go b/protocol/messenger_handler.go index e373cba3f..c8c742825 100644 --- a/protocol/messenger_handler.go +++ b/protocol/messenger_handler.go @@ -43,6 +43,8 @@ var ( ErrWalletAccountNotSupportedForMobileApp = errors.New("handling account is not supported for mobile app") ErrTryingToStoreOldWalletAccount = errors.New("trying to store an old wallet account") ErrSomeFieldsMissingForWalletAccount = errors.New("some fields are missing for wallet account") + ErrTryingToRemoveUnexistingWalletAccount = errors.New("trying to remove an unexisting wallet account") + ErrUnknownKeypairForWalletAccount = errors.New("keypair is not known for the wallet account") ) // HandleMembershipUpdate updates a Chat instance according to the membership updates. @@ -2871,49 +2873,101 @@ func (m *Messenger) updateUnviewedCounts(chat *Chat, mentionedOrReplied bool) { chat.UnviewedMentionsCount++ } } +func mapSyncAccountToAccount(message *protobuf.SyncAccount, accountOperability accounts.AccountOperable) *accounts.Account { + return &accounts.Account{ + Address: types.BytesToAddress(message.Address), + KeyUID: message.KeyUid, + PublicKey: types.HexBytes(message.PublicKey), + Path: message.Path, + Name: message.Name, + Color: message.Color, + Emoji: message.Emoji, + Wallet: message.Wallet, + Chat: message.Chat, + Hidden: message.Hidden, + Clock: message.Clock, + Operable: accountOperability, + } +} -func (m *Messenger) handleSyncWalletAccount(message *protobuf.SyncWalletAccount) (*accounts.Account, error) { +func (m *Messenger) resolveAccountOperability(keyUID string, defaultWalletAccount bool, accountReceivedFromRecovering bool) (accounts.AccountOperable, error) { + knownKeycardsForKeyUID, err := m.settings.GetKeycardByKeyUID(keyUID) + if err != nil { + if err == accounts.ErrDbKeypairNotFound { + return accounts.AccountNonOperable, nil + } + return accounts.AccountNonOperable, err + } + + keypairMigratedToKeycard := len(knownKeycardsForKeyUID) > 0 + accountsOperability := accounts.AccountNonOperable + if keypairMigratedToKeycard || accountReceivedFromRecovering || defaultWalletAccount { + accountsOperability = accounts.AccountFullyOperable + } else { + partiallyOrFullyOperable, err := m.settings.IsAnyAccountPartalyOrFullyOperableForKeyUID(keyUID) + if err != nil { + if err == accounts.ErrDbKeypairNotFound { + return accounts.AccountNonOperable, nil + } + return accounts.AccountNonOperable, err + } + if partiallyOrFullyOperable { + accountsOperability = accounts.AccountPartiallyOperable + } + } + + return accountsOperability, nil +} + +func (m *Messenger) handleSyncWalletAccount(message *protobuf.SyncAccount, syncedFrom string) (*accounts.Account, error) { if message.Chat { return nil, ErrNotWalletAccount } + + accountOperability := accounts.AccountFullyOperable + + // The only account without `KeyUid` is watch only account and it doesn't belong to any keypair. + if message.KeyUid != "" { + _, err := m.settings.GetKeypairByKeyUID(message.KeyUid) + if err != nil { + if err == accounts.ErrDbKeypairNotFound { + return nil, ErrUnknownKeypairForWalletAccount + } + return nil, err + } + + accountReceivedFromRecovering := syncedFrom == accounts.SyncedFromLocalPairing + accountOperability, err = m.resolveAccountOperability(message.KeyUid, message.Wallet, accountReceivedFromRecovering) + if err != nil { + return nil, err + } + } + accAddress := types.BytesToAddress(message.Address) dbAccount, err := m.settings.GetAccountByAddress(accAddress) - if err != nil && err != sql.ErrNoRows { + if err != nil && err != accounts.ErrDbAccountNotFound { return nil, err } - if dbAccount != nil && message.Clock <= dbAccount.Clock { - return nil, ErrTryingToStoreOldWalletAccount - } - - var acc *accounts.Account - if dbAccount != nil && message.Removed { - acc = &accounts.Account{ - Address: types.BytesToAddress(message.Address), - Removed: true, + if dbAccount != nil { + if message.Clock <= dbAccount.Clock { + return nil, ErrTryingToStoreOldWalletAccount } - } else if !message.Removed { - acc = &accounts.Account{ - Address: types.BytesToAddress(message.Address), - Wallet: message.Wallet, - Chat: message.Chat, - Type: accounts.AccountType(message.Type), - Storage: message.Storage, - PublicKey: types.HexBytes(message.PublicKey), - Path: message.Path, - Color: message.Color, - Hidden: message.Hidden, - Name: message.Name, - Clock: message.Clock, - KeyUID: message.KeyUid, - Emoji: message.Emoji, - DerivedFrom: message.DerivedFrom, - KeypairName: message.KeypairName, - LastUsedDerivationIndex: message.LastUsedDerivationIndex, + + if message.Removed { + err = m.settings.DeleteAccount(accAddress) + dbAccount.Removed = true + return dbAccount, err + } + } else { + if message.Removed { + return nil, ErrTryingToRemoveUnexistingWalletAccount } } - err = m.settings.SaveAccounts([]*accounts.Account{acc}) + acc := mapSyncAccountToAccount(message, accountOperability) + + err = m.settings.SaveOrUpdateAccounts([]*accounts.Account{acc}) if err != nil { return nil, err } @@ -2921,24 +2975,132 @@ func (m *Messenger) handleSyncWalletAccount(message *protobuf.SyncWalletAccount) return acc, nil } -func (m *Messenger) HandleSyncWalletAccount(state *ReceivedMessageState, message protobuf.SyncWalletAccounts) error { - var accs []*accounts.Account - for _, accMsg := range message.Accounts { - acc, err := m.handleSyncWalletAccount(accMsg) - if err != nil { - if err == ErrNotWalletAccount || - err == ErrWalletAccountNotSupportedForMobileApp || - err == ErrTryingToStoreOldWalletAccount || - err == ErrSomeFieldsMissingForWalletAccount { - continue - } - return err - } - - accs = append(accs, acc) +func (m *Messenger) handleSyncKeypair(message *protobuf.SyncKeypair) (*accounts.Keypair, error) { + dbKeypair, err := m.settings.GetKeypairByKeyUID(message.KeyUid) + if err != nil && err != accounts.ErrDbKeypairNotFound { + return nil, err } - state.Response.Accounts = accs + kp := &accounts.Keypair{ + KeyUID: message.KeyUid, + Name: message.Name, + Type: accounts.KeypairType(message.Type), + DerivedFrom: message.DerivedFrom, + LastUsedDerivationIndex: message.LastUsedDerivationIndex, + SyncedFrom: message.SyncedFrom, + Clock: message.Clock, + } + + saveOrUpdate := dbKeypair == nil + if dbKeypair != nil { + saveOrUpdate = dbKeypair.Clock < kp.Clock + // in case of keypair update, we need to keep `synced_from` field as it was when keypair was introduced to this device for the first time + kp.SyncedFrom = dbKeypair.SyncedFrom + } + + if saveOrUpdate { + accountReceivedFromRecovering := message.SyncedFrom == accounts.SyncedFromLocalPairing + if dbKeypair != nil && message.SyncedFrom == accounts.SyncedFromBackup { + // in case of recovering from backed up messages we need to delete messages which are already in db (eg. stored py previously received backed up message) + for _, dbAcc := range dbKeypair.Accounts { + found := false + for _, sAcc := range message.Accounts { + sAccAddress := types.BytesToAddress(sAcc.Address) + if dbAcc.Address == sAccAddress { + found = true + break + } + } + if found { + err = m.settings.DeleteAccount(dbAcc.Address) + if err != nil { + return nil, err + } + } + } + } + + for _, sAcc := range message.Accounts { + accountOperability, err := m.resolveAccountOperability(sAcc.KeyUid, sAcc.Wallet, accountReceivedFromRecovering) + if err != nil { + return nil, err + } + acc := mapSyncAccountToAccount(sAcc, accountOperability) + kp.Accounts = append(kp.Accounts, acc) + } + err = m.settings.SaveOrUpdateKeypair(kp) + if err != nil { + return nil, err + } + } + + for _, sAcc := range message.Accounts { + acc, err := m.handleSyncWalletAccount(sAcc, message.SyncedFrom) + if err != nil { + if err == ErrNotWalletAccount || + err == ErrTryingToStoreOldWalletAccount || + err == ErrTryingToRemoveUnexistingWalletAccount { + continue + } + return nil, err + } + + kp.Accounts = append(kp.Accounts, acc) + } + + return kp, nil +} + +func (m *Messenger) handleSyncKeypairFull(message *protobuf.SyncKeypairFull) (kp *accounts.Keypair, keycards []*accounts.Keycard, err error) { + kp, err = m.handleSyncKeypair(message.Keypair) + if err != nil { + return nil, nil, err + } + + for _, sKc := range message.Keycards { + kc := accounts.Keycard{} + kc.FromSyncKeycard(sKc) + keycards = append(keycards, &kc) + } + + err = m.settings.ApplyKeycardsForKeypairWithKeyUID(kp.KeyUID, keycards) + if err != nil { + return kp, keycards, err + } + + return +} + +func (m *Messenger) HandleSyncWalletAccount(state *ReceivedMessageState, message protobuf.SyncAccount, syncedFrom string) error { + acc, err := m.handleSyncWalletAccount(&message, syncedFrom) + if err != nil { + return err + } + + state.Response.Accounts = append(state.Response.Accounts, acc) + + return nil +} + +func (m *Messenger) HandleSyncKeypair(state *ReceivedMessageState, message protobuf.SyncKeypair) error { + kp, err := m.handleSyncKeypair(&message) + if err != nil { + return err + } + + state.Response.Keypairs = append(state.Response.Keypairs, kp) + + return nil +} + +func (m *Messenger) HandleSyncKeypairFull(state *ReceivedMessageState, message protobuf.SyncKeypairFull) error { + keypair, keycards, err := m.handleSyncKeypairFull(&message) + if err != nil { + return err + } + + state.Response.Keypairs = append(state.Response.Keypairs, keypair) + state.Response.Keycards = append(state.Response.Keycards, keycards...) return nil } diff --git a/protocol/messenger_keycard.go b/protocol/messenger_keycard.go index cf9927b2a..4ede8a978 100644 --- a/protocol/messenger_keycard.go +++ b/protocol/messenger_keycard.go @@ -6,101 +6,28 @@ import ( "github.com/golang/protobuf/proto" "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/multiaccounts/keycards" + "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) dispatchSyncKeycard(ctx context.Context, chatID string, syncKeycard protobuf.SyncAllKeycards, - rawMessageHandler RawMessageHandler) error { - if !m.hasPairedDevices() { - return nil - } - - encodedMessage, err := proto.Marshal(&syncKeycard) - if err != nil { - return err - } - - rawMessage := common.RawMessage{ - LocalChatID: chatID, - Payload: encodedMessage, - MessageType: protobuf.ApplicationMetadataMessage_SYNC_ALL_KEYCARDS, - ResendAutomatically: true, - } - - _, err = rawMessageHandler(ctx, rawMessage) - return err -} - -func (m *Messenger) prepareSyncAllKeycardsMessage(clock uint64) (message protobuf.SyncAllKeycards, err error) { +func (m *Messenger) prepareSyncKeycardsMessage(keyUID string) (message []*protobuf.SyncKeycard, err error) { allKeycards, err := m.settings.GetAllKnownKeycards() if err != nil { return message, err } - message.Clock = clock - for _, kc := range allKeycards { - syncKeycard := kc.ToSyncKeycard() - if syncKeycard.Clock == 0 { - syncKeycard.Clock = clock + if kc.KeyUID != keyUID { + continue } - message.Keycards = append(message.Keycards, syncKeycard) + syncKeycard := kc.ToSyncKeycard() + message = append(message, syncKeycard) } return } -func (m *Messenger) syncAllKeycards(ctx context.Context, rawMessageHandler RawMessageHandler) (err error) { - clock, chat := m.getLastClockWithRelatedChat() - - message, err := m.prepareSyncAllKeycardsMessage(clock) - if err != nil { - return err - } - - err = m.dispatchSyncKeycard(ctx, chat.ID, message, rawMessageHandler) - if err != nil { - return err - } - - chat.LastClockValue = clock - return m.saveChat(chat) -} - -func (m *Messenger) syncReceivedKeycards(syncMessage protobuf.SyncAllKeycards) ([]*keycards.Keycard, error) { - var keycardsToSync []*keycards.Keycard - for _, syncKc := range syncMessage.Keycards { - var kp = &keycards.Keycard{} - kp.FromSyncKeycard(syncKc) - keycardsToSync = append(keycardsToSync, kp) - } - - err := m.settings.SyncKeycards(syncMessage.Clock, keycardsToSync) - if err != nil { - return nil, err - } - - allKeycards, err := m.settings.GetAllKnownKeycards() - if err != nil { - return nil, err - } - - return allKeycards, nil -} - -func (m *Messenger) handleSyncKeycards(state *ReceivedMessageState, syncMessage protobuf.SyncAllKeycards) (err error) { - allKeycards, err := m.syncReceivedKeycards(syncMessage) - if err != nil { - return err - } - - state.Response.AddAllKnownKeycards(allKeycards) - - return nil -} - func (m *Messenger) dispatchKeycardActivity(ctx context.Context, syncMessage protobuf.SyncKeycardAction) error { if !m.hasPairedDevices() { return nil @@ -131,10 +58,10 @@ func (m *Messenger) dispatchKeycardActivity(ctx context.Context, syncMessage pro func (m *Messenger) handleSyncKeycardActivity(state *ReceivedMessageState, syncMessage protobuf.SyncKeycardAction) (err error) { - var kcAction = &keycards.KeycardAction{ + var kcAction = &accounts.KeycardAction{ Action: protobuf.SyncKeycardAction_Action_name[int32(syncMessage.Action)], OldKeycardUID: syncMessage.OldKeycardUid, - Keycard: &keycards.Keycard{}, + Keycard: &accounts.Keycard{}, } kcAction.Keycard.FromSyncKeycard(syncMessage.Keycard) @@ -170,7 +97,7 @@ func (m *Messenger) handleSyncKeycardActivity(state *ReceivedMessageState, syncM return nil } -func (m *Messenger) AddKeycardOrAddAccountsIfKeycardIsAdded(ctx context.Context, kp *keycards.Keycard) (added bool, err error) { +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 diff --git a/protocol/messenger_response.go b/protocol/messenger_response.go index ad390e9dd..26f33b2a7 100644 --- a/protocol/messenger_response.go +++ b/protocol/messenger_response.go @@ -13,7 +13,6 @@ import ( "github.com/status-im/status-go/appmetrics" "github.com/status-im/status-go/images" "github.com/status-im/status-go/multiaccounts/accounts" - "github.com/status-im/status-go/multiaccounts/keycards" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/communities" @@ -48,6 +47,7 @@ type MessengerResponse struct { Settings []*settings.SyncSettingField IdentityImages []images.IdentityImage Accounts []*accounts.Account + Keypairs []*accounts.Keypair DiscordCategories []*discord.Category DiscordChannels []*discord.Channel DiscordOldestMessageTimestamp int @@ -75,8 +75,8 @@ type MessengerResponse struct { trustStatus map[string]verification.TrustStatus emojiReactions map[string]*EmojiReaction savedAddresses map[string]*wallet.SavedAddress - keycards []*keycards.Keycard - keycardActions []*keycards.KeycardAction + Keycards []*accounts.Keycard + keycardActions []*accounts.KeycardAction socialLinkSettings []*identity.SocialLink ensUsernameDetails []*ensservice.UsernameDetail } @@ -111,14 +111,15 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) { Settings []*settings.SyncSettingField `json:"settings,omitempty"` IdentityImages []images.IdentityImage `json:"identityImages,omitempty"` Accounts []*accounts.Account `json:"accounts,omitempty"` + Keypairs []*accounts.Keypair `json:"keypairs,omitempty"` DiscordCategories []*discord.Category `json:"discordCategories,omitempty"` DiscordChannels []*discord.Channel `json:"discordChannels,omitempty"` DiscordOldestMessageTimestamp int `json:"discordOldestMessageTimestamp"` DiscordMessages []*protobuf.DiscordMessage `json:"discordMessages,omitempty"` DiscordMessageAttachments []*protobuf.DiscordMessageAttachment `json:"discordMessageAtachments,omitempty"` SavedAddresses []*wallet.SavedAddress `json:"savedAddresses,omitempty"` - Keycards []*keycards.Keycard `json:"keycards,omitempty"` - KeycardActions []*keycards.KeycardAction `json:"keycardActions,omitempty"` + Keycards []*accounts.Keycard `json:"keycards,omitempty"` + KeycardActions []*accounts.KeycardAction `json:"keycardActions,omitempty"` SocialLinkSettings []*identity.SocialLink `json:"socialLinkSettings,omitempty"` EnsUsernameDetails []*ensservice.UsernameDetail `json:"ensUsernameDetails,omitempty"` }{ @@ -133,6 +134,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) { Settings: r.Settings, IdentityImages: r.IdentityImages, Accounts: r.Accounts, + Keypairs: r.Keypairs, Messages: r.Messages(), VerificationRequests: r.VerificationRequests(), @@ -152,7 +154,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) { DiscordCategories: r.DiscordCategories, DiscordChannels: r.DiscordChannels, DiscordOldestMessageTimestamp: r.DiscordOldestMessageTimestamp, - Keycards: r.AllKnownKeycards(), + Keycards: r.Keycards, KeycardActions: r.KeycardActions(), SocialLinkSettings: r.SocialLinkSettings(), EnsUsernameDetails: r.EnsUsernameDetails(), @@ -273,6 +275,7 @@ func (r *MessengerResponse) IsEmpty() bool { len(r.Mailservers)+ len(r.IdentityImages)+ len(r.Accounts)+ + len(r.Keypairs)+ len(r.notifications)+ len(r.statusUpdates)+ len(r.activityCenterNotifications)+ @@ -280,7 +283,7 @@ func (r *MessengerResponse) IsEmpty() bool { len(r.verificationRequests)+ len(r.RequestsToJoinCommunity)+ len(r.savedAddresses)+ - len(r.keycards)+ + len(r.Keycards)+ len(r.keycardActions) == 0 && len(r.socialLinkSettings) == 0 && len(r.ensUsernameDetails) == 0 && @@ -315,13 +318,15 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error { r.AddEmojiReactions(response.EmojiReactions()) r.AddInstallations(response.Installations) r.AddSavedAddresses(response.SavedAddresses()) - r.AddAllKnownKeycards(response.AllKnownKeycards()) r.AddKeycardActions(response.KeycardActions()) r.AddSocialLinkSettings(response.SocialLinkSettings()) r.AddEnsUsernameDetails(response.EnsUsernameDetails()) r.AddBookmarks(response.GetBookmarks()) r.CommunityChanges = append(r.CommunityChanges, response.CommunityChanges...) r.BackupHandled = response.BackupHandled + r.Accounts = append(r.Accounts, response.Accounts...) + r.Keypairs = append(r.Keypairs, response.Keypairs...) + r.Keycards = append(r.Keycards, response.Keycards...) return nil } @@ -460,23 +465,15 @@ func (r *MessengerResponse) SavedAddresses() []*wallet.SavedAddress { return ers } -func (r *MessengerResponse) AddAllKnownKeycards(keycards []*keycards.Keycard) { - r.keycards = append(r.keycards, keycards...) -} - -func (r *MessengerResponse) AllKnownKeycards() []*keycards.Keycard { - return r.keycards -} - -func (r *MessengerResponse) AddKeycardAction(keycardAction *keycards.KeycardAction) { +func (r *MessengerResponse) AddKeycardAction(keycardAction *accounts.KeycardAction) { r.keycardActions = append(r.keycardActions, keycardAction) } -func (r *MessengerResponse) AddKeycardActions(keycardActions []*keycards.KeycardAction) { +func (r *MessengerResponse) AddKeycardActions(keycardActions []*accounts.KeycardAction) { r.keycardActions = append(r.keycardActions, keycardActions...) } -func (r *MessengerResponse) KeycardActions() []*keycards.KeycardAction { +func (r *MessengerResponse) KeycardActions() []*accounts.KeycardAction { return r.keycardActions } diff --git a/protocol/messenger_sync_raw_messages.go b/protocol/messenger_sync_raw_messages.go index 3f751af64..5555a2cf9 100644 --- a/protocol/messenger_sync_raw_messages.go +++ b/protocol/messenger_sync_raw_messages.go @@ -7,6 +7,7 @@ import ( "github.com/golang/protobuf/proto" "go.uber.org/zap" + "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/encryption/multidevice" "github.com/status-im/status-go/protocol/protobuf" @@ -192,17 +193,28 @@ func (m *Messenger) HandleSyncRawMessages(rawMessages []*protobuf.RawMessage) er m.logger.Error("failed to HandleSyncContactRequestDecision when HandleSyncRawMessages", zap.Error(err)) continue } - case protobuf.ApplicationMetadataMessage_SYNC_WALLET_ACCOUNT: - var message protobuf.SyncWalletAccounts + case protobuf.ApplicationMetadataMessage_SYNC_ACCOUNT: + var message protobuf.SyncAccount err := proto.Unmarshal(rawMessage.GetPayload(), &message) if err != nil { return err } - err = m.HandleSyncWalletAccount(state, message) + err = m.HandleSyncWalletAccount(state, message, accounts.SyncedFromLocalPairing) if err != nil { m.logger.Error("failed to HandleSyncWalletAccount when HandleSyncRawMessages", zap.Error(err)) continue } + case protobuf.ApplicationMetadataMessage_SYNC_FULL_KEYPAIR: + var message protobuf.SyncKeypairFull + err := proto.Unmarshal(rawMessage.GetPayload(), &message) + if err != nil { + return err + } + err = m.HandleSyncKeypairFull(state, message) + if err != nil { + m.logger.Error("failed to HandleSyncKeypairFull when HandleSyncRawMessages", zap.Error(err)) + continue + } case protobuf.ApplicationMetadataMessage_SYNC_SAVED_ADDRESS: var message protobuf.SyncSavedAddress err := proto.Unmarshal(rawMessage.GetPayload(), &message) @@ -214,17 +226,6 @@ func (m *Messenger) HandleSyncRawMessages(rawMessages []*protobuf.RawMessage) er m.logger.Error("failed to handleSyncSavedAddress when HandleSyncRawMessages", zap.Error(err)) continue } - case protobuf.ApplicationMetadataMessage_SYNC_ALL_KEYCARDS: - var message protobuf.SyncAllKeycards - err := proto.Unmarshal(rawMessage.GetPayload(), &message) - if err != nil { - return err - } - err = m.handleSyncKeycards(state, message) - if err != nil { - m.logger.Error("failed to handleSyncKeycards when HandleSyncRawMessages", zap.Error(err)) - continue - } case protobuf.ApplicationMetadataMessage_SYNC_SOCIAL_LINK_SETTING: var message protobuf.SyncSocialLinkSetting err := proto.Unmarshal(rawMessage.GetPayload(), &message) diff --git a/protocol/messenger_wallet.go b/protocol/messenger_wallet.go index a2aa6e141..9c604291b 100644 --- a/protocol/messenger_wallet.go +++ b/protocol/messenger_wallet.go @@ -2,6 +2,7 @@ package protocol import ( "context" + "errors" "time" "github.com/golang/protobuf/proto" @@ -11,6 +12,7 @@ import ( "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/encryption/multidevice" "github.com/status-im/status-go/protocol/protobuf" ) @@ -71,15 +73,30 @@ func (m *Messenger) watchWalletBalances() { }() } -func (m *Messenger) SaveAccount(acc *accounts.Account) error { +func (m *Messenger) SaveOrUpdateKeypair(keypair *accounts.Keypair) error { clock, _ := m.getLastClockWithRelatedChat() - acc.Clock = clock + keypair.Clock = clock - err := m.settings.SaveAccounts([]*accounts.Account{acc}) + for _, acc := range keypair.Accounts { + acc.Clock = clock + } + + err := m.settings.SaveOrUpdateKeypair(keypair) if err != nil { return err } - return m.syncWallets([]*accounts.Account{acc}, m.dispatchMessage) + return m.syncKeypair(keypair, false, m.dispatchMessage) +} + +func (m *Messenger) SaveOrUpdateAccount(acc *accounts.Account) error { + clock, _ := m.getLastClockWithRelatedChat() + acc.Clock = clock + + err := m.settings.SaveOrUpdateAccounts([]*accounts.Account{acc}) + if err != nil { + return err + } + return m.syncWalletAccount(acc, m.dispatchMessage) } func (m *Messenger) DeleteAccount(address types.Address) error { @@ -98,8 +115,7 @@ func (m *Messenger) DeleteAccount(address types.Address) error { acc.Clock = clock acc.Removed = true - accs := []*accounts.Account{acc} - err = m.syncWallets(accs, m.dispatchMessage) + err = m.syncWalletAccount(acc, m.dispatchMessage) if err != nil { return err } @@ -108,43 +124,89 @@ func (m *Messenger) DeleteAccount(address types.Address) error { return m.saveChat(chat) } -func (m *Messenger) prepareSyncWalletAccountsMessage(accs []*accounts.Account) *protobuf.SyncWalletAccounts { - accountMessages := make([]*protobuf.SyncWalletAccount, 0) - for _, acc := range accs { - if acc.Chat { - continue - } - - syncMessage := &protobuf.SyncWalletAccount{ - Clock: acc.Clock, - Address: acc.Address.Bytes(), - Wallet: acc.Wallet, - Chat: acc.Chat, - Type: acc.Type.String(), - Storage: acc.Storage, - Path: acc.Path, - PublicKey: acc.PublicKey, - Name: acc.Name, - Color: acc.Color, - Hidden: acc.Hidden, - Removed: acc.Removed, - Emoji: acc.Emoji, - DerivedFrom: acc.DerivedFrom, - KeyUid: acc.KeyUID, - KeypairName: acc.KeypairName, - LastUsedDerivationIndex: acc.LastUsedDerivationIndex, - } - - accountMessages = append(accountMessages, syncMessage) +func (m *Messenger) prepareSyncAccountMessage(acc *accounts.Account) *protobuf.SyncAccount { + if acc.Chat { + return nil } - return &protobuf.SyncWalletAccounts{ - Accounts: accountMessages, + return &protobuf.SyncAccount{ + Clock: acc.Clock, + Address: acc.Address.Bytes(), + KeyUid: acc.KeyUID, + PublicKey: acc.PublicKey, + Path: acc.Path, + Name: acc.Name, + Color: acc.Color, + Emoji: acc.Emoji, + Wallet: acc.Wallet, + Chat: acc.Chat, + Hidden: acc.Hidden, + Removed: acc.Removed, } } -// syncWallets syncs all wallets with paired devices -func (m *Messenger) syncWallets(accs []*accounts.Account, rawMessageHandler RawMessageHandler) error { +func (m *Messenger) getMyInstallationMetadata() (*multidevice.InstallationMetadata, error) { + installation, ok := m.allInstallations.Load(m.installationID) + if !ok { + return nil, errors.New("no installation found") + } + + if installation.InstallationMetadata == nil { + return nil, errors.New("no installation metadata") + } + + return installation.InstallationMetadata, nil +} + +func (m *Messenger) prepareSyncKeypairMessage(kp *accounts.Keypair) (*protobuf.SyncKeypair, error) { + message := &protobuf.SyncKeypair{ + Clock: kp.Clock, + KeyUid: kp.KeyUID, + Name: kp.Name, + Type: kp.Type.String(), + DerivedFrom: kp.DerivedFrom, + LastUsedDerivationIndex: kp.LastUsedDerivationIndex, + SyncedFrom: kp.SyncedFrom, + } + + if kp.SyncedFrom == "" { + installationMetadata, err := m.getMyInstallationMetadata() + if err != nil { + return nil, err + } + message.SyncedFrom = installationMetadata.Name + } + + for _, acc := range kp.Accounts { + sAcc := m.prepareSyncAccountMessage(acc) + if sAcc == nil { + continue + } + + message.Accounts = append(message.Accounts, sAcc) + } + + return message, nil +} + +func (m *Messenger) prepareSyncKeypairFullMessage(kp *accounts.Keypair) (*protobuf.SyncKeypairFull, error) { + syncKpMsg, err := m.prepareSyncKeypairMessage(kp) + if err != nil { + return nil, err + } + + syncKcMsgs, err := m.prepareSyncKeycardsMessage(kp.KeyUID) + if err != nil { + return nil, err + } + + return &protobuf.SyncKeypairFull{ + Keypair: syncKpMsg, + Keycards: syncKcMsgs, + }, nil +} + +func (m *Messenger) syncWalletAccount(acc *accounts.Account, rawMessageHandler RawMessageHandler) error { if !m.hasPairedDevices() { return nil } @@ -154,7 +216,7 @@ func (m *Messenger) syncWallets(accs []*accounts.Account, rawMessageHandler RawM _, chat := m.getLastClockWithRelatedChat() - message := m.prepareSyncWalletAccountsMessage(accs) + message := m.prepareSyncAccountMessage(acc) encodedMessage, err := proto.Marshal(message) if err != nil { @@ -164,10 +226,52 @@ func (m *Messenger) syncWallets(accs []*accounts.Account, rawMessageHandler RawM rawMessage := common.RawMessage{ LocalChatID: chat.ID, Payload: encodedMessage, - MessageType: protobuf.ApplicationMetadataMessage_SYNC_WALLET_ACCOUNT, + MessageType: protobuf.ApplicationMetadataMessage_SYNC_ACCOUNT, ResendAutomatically: true, } _, err = rawMessageHandler(ctx, rawMessage) return err } + +func (m *Messenger) syncKeypair(keypair *accounts.Keypair, fullKeypairSync bool, rawMessageHandler RawMessageHandler) (err error) { + if !m.hasPairedDevices() { + return nil + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + _, chat := m.getLastClockWithRelatedChat() + rawMessage := common.RawMessage{ + LocalChatID: chat.ID, + ResendAutomatically: true, + } + + if fullKeypairSync { + message, err := m.prepareSyncKeypairFullMessage(keypair) + if err != nil { + return err + } + + rawMessage.MessageType = protobuf.ApplicationMetadataMessage_SYNC_FULL_KEYPAIR + rawMessage.Payload, err = proto.Marshal(message) + if err != nil { + return err + } + } else { + message, err := m.prepareSyncKeypairMessage(keypair) + if err != nil { + return err + } + + rawMessage.MessageType = protobuf.ApplicationMetadataMessage_SYNC_KEYPAIR + rawMessage.Payload, err = proto.Marshal(message) + if err != nil { + return err + } + } + + _, err = rawMessageHandler(ctx, rawMessage) + return err +} diff --git a/protocol/protobuf/application_metadata_message.pb.go b/protocol/protobuf/application_metadata_message.pb.go index 8f48514bd..94a9d5285 100644 --- a/protocol/protobuf/application_metadata_message.pb.go +++ b/protocol/protobuf/application_metadata_message.pb.go @@ -68,7 +68,7 @@ const ( ApplicationMetadataMessage_SYNC_SETTING ApplicationMetadataMessage_Type = 42 ApplicationMetadataMessage_COMMUNITY_ARCHIVE_MAGNETLINK ApplicationMetadataMessage_Type = 43 ApplicationMetadataMessage_SYNC_PROFILE_PICTURE ApplicationMetadataMessage_Type = 44 - ApplicationMetadataMessage_SYNC_WALLET_ACCOUNT ApplicationMetadataMessage_Type = 45 + ApplicationMetadataMessage_SYNC_ACCOUNT ApplicationMetadataMessage_Type = 45 ApplicationMetadataMessage_ACCEPT_CONTACT_REQUEST ApplicationMetadataMessage_Type = 46 ApplicationMetadataMessage_RETRACT_CONTACT_REQUEST ApplicationMetadataMessage_Type = 47 ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN_RESPONSE ApplicationMetadataMessage_Type = 48 @@ -84,10 +84,11 @@ const ( ApplicationMetadataMessage_SYNC_SAVED_ADDRESS ApplicationMetadataMessage_Type = 59 ApplicationMetadataMessage_COMMUNITY_CANCEL_REQUEST_TO_JOIN ApplicationMetadataMessage_Type = 60 ApplicationMetadataMessage_CANCEL_CONTACT_VERIFICATION ApplicationMetadataMessage_Type = 61 - ApplicationMetadataMessage_SYNC_ALL_KEYCARDS ApplicationMetadataMessage_Type = 62 + ApplicationMetadataMessage_SYNC_KEYPAIR ApplicationMetadataMessage_Type = 62 ApplicationMetadataMessage_SYNC_KEYCARD_ACTION ApplicationMetadataMessage_Type = 63 ApplicationMetadataMessage_SYNC_SOCIAL_LINK_SETTING ApplicationMetadataMessage_Type = 64 ApplicationMetadataMessage_SYNC_ENS_USERNAME_DETAIL ApplicationMetadataMessage_Type = 65 + ApplicationMetadataMessage_SYNC_FULL_KEYPAIR ApplicationMetadataMessage_Type = 66 ) var ApplicationMetadataMessage_Type_name = map[int32]string{ @@ -136,7 +137,7 @@ var ApplicationMetadataMessage_Type_name = map[int32]string{ 42: "SYNC_SETTING", 43: "COMMUNITY_ARCHIVE_MAGNETLINK", 44: "SYNC_PROFILE_PICTURE", - 45: "SYNC_WALLET_ACCOUNT", + 45: "SYNC_ACCOUNT", 46: "ACCEPT_CONTACT_REQUEST", 47: "RETRACT_CONTACT_REQUEST", 48: "COMMUNITY_REQUEST_TO_JOIN_RESPONSE", @@ -152,10 +153,11 @@ var ApplicationMetadataMessage_Type_name = map[int32]string{ 59: "SYNC_SAVED_ADDRESS", 60: "COMMUNITY_CANCEL_REQUEST_TO_JOIN", 61: "CANCEL_CONTACT_VERIFICATION", - 62: "SYNC_ALL_KEYCARDS", + 62: "SYNC_KEYPAIR", 63: "SYNC_KEYCARD_ACTION", 64: "SYNC_SOCIAL_LINK_SETTING", 65: "SYNC_ENS_USERNAME_DETAIL", + 66: "SYNC_FULL_KEYPAIR", } var ApplicationMetadataMessage_Type_value = map[string]int32{ @@ -204,7 +206,7 @@ var ApplicationMetadataMessage_Type_value = map[string]int32{ "SYNC_SETTING": 42, "COMMUNITY_ARCHIVE_MAGNETLINK": 43, "SYNC_PROFILE_PICTURE": 44, - "SYNC_WALLET_ACCOUNT": 45, + "SYNC_ACCOUNT": 45, "ACCEPT_CONTACT_REQUEST": 46, "RETRACT_CONTACT_REQUEST": 47, "COMMUNITY_REQUEST_TO_JOIN_RESPONSE": 48, @@ -220,10 +222,11 @@ var ApplicationMetadataMessage_Type_value = map[string]int32{ "SYNC_SAVED_ADDRESS": 59, "COMMUNITY_CANCEL_REQUEST_TO_JOIN": 60, "CANCEL_CONTACT_VERIFICATION": 61, - "SYNC_ALL_KEYCARDS": 62, + "SYNC_KEYPAIR": 62, "SYNC_KEYCARD_ACTION": 63, "SYNC_SOCIAL_LINK_SETTING": 64, "SYNC_ENS_USERNAME_DETAIL": 65, + "SYNC_FULL_KEYPAIR": 66, } func (x ApplicationMetadataMessage_Type) String() string { @@ -302,65 +305,65 @@ func init() { } var fileDescriptor_ad09a6406fcf24c7 = []byte{ - // 957 bytes of a gzipped FileDescriptorProto + // 959 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0x6b, 0x73, 0x13, 0x37, - 0x14, 0x6d, 0x80, 0x26, 0xa0, 0xbc, 0x14, 0x91, 0x87, 0xf3, 0x36, 0x86, 0x86, 0x00, 0xad, 0x69, - 0xa1, 0xed, 0xb4, 0xa5, 0xb4, 0x95, 0xa5, 0x1b, 0x5b, 0x78, 0x57, 0x5a, 0x24, 0xad, 0x19, 0xf7, - 0x8b, 0xc6, 0x14, 0x97, 0xc9, 0x0c, 0x10, 0x0f, 0x31, 0x1f, 0xf2, 0xff, 0xfa, 0x2b, 0xfa, 0x6b, - 0x3a, 0xda, 0x87, 0xd6, 0x49, 0x9c, 0xf2, 0x29, 0xd9, 0x7b, 0x8e, 0xae, 0x74, 0xcf, 0x3d, 0xf7, - 0x1a, 0x35, 0x06, 0xa3, 0xd1, 0xbb, 0xe3, 0xbf, 0x06, 0xe3, 0xe3, 0x93, 0x0f, 0xee, 0xfd, 0x70, - 0x3c, 0x78, 0x33, 0x18, 0x0f, 0xdc, 0xfb, 0xe1, 0xe9, 0xe9, 0xe0, 0xed, 0xb0, 0x39, 0xfa, 0x78, - 0x32, 0x3e, 0x21, 0x37, 0xb3, 0x3f, 0xaf, 0x3f, 0xfd, 0xdd, 0xf8, 0x77, 0x19, 0x6d, 0xd1, 0xea, - 0x40, 0x5c, 0xf0, 0xe3, 0x9c, 0x4e, 0x76, 0xd0, 0xad, 0xd3, 0xe3, 0xb7, 0x1f, 0x06, 0xe3, 0x4f, - 0x1f, 0x87, 0xb5, 0x99, 0xfa, 0xcc, 0xe1, 0x82, 0xae, 0x02, 0xa4, 0x86, 0xe6, 0x46, 0x83, 0xb3, - 0x77, 0x27, 0x83, 0x37, 0xb5, 0x6b, 0x19, 0x56, 0x7e, 0x92, 0xe7, 0xe8, 0xc6, 0xf8, 0x6c, 0x34, - 0xac, 0x5d, 0xaf, 0xcf, 0x1c, 0x2e, 0x3d, 0x79, 0xd0, 0x2c, 0xef, 0x6b, 0x5e, 0x7d, 0x57, 0xd3, - 0x9e, 0x8d, 0x86, 0x3a, 0x3b, 0xd6, 0xf8, 0x67, 0x09, 0xdd, 0xf0, 0x9f, 0x64, 0x1e, 0xcd, 0xa5, - 0xb2, 0x2b, 0xd5, 0x2b, 0x89, 0xbf, 0x20, 0x18, 0x2d, 0xb0, 0x0e, 0xb5, 0x2e, 0x06, 0x63, 0x68, - 0x1b, 0xf0, 0x0c, 0x21, 0x68, 0x89, 0x29, 0x69, 0x29, 0xb3, 0x2e, 0x4d, 0x38, 0xb5, 0x80, 0xaf, - 0x91, 0x5d, 0xb4, 0x19, 0x43, 0xdc, 0x02, 0x6d, 0x3a, 0x22, 0x29, 0xc2, 0xe1, 0xc8, 0x75, 0xb2, - 0x86, 0x56, 0x12, 0x2a, 0xb4, 0x13, 0xd2, 0x58, 0x1a, 0x45, 0xd4, 0x0a, 0x25, 0xf1, 0x0d, 0x1f, - 0x36, 0x7d, 0xc9, 0xce, 0x87, 0xbf, 0x24, 0x77, 0xd1, 0xbe, 0x86, 0x97, 0x29, 0x18, 0xeb, 0x28, - 0xe7, 0x1a, 0x8c, 0x71, 0x47, 0x4a, 0x3b, 0xab, 0xa9, 0x34, 0x94, 0x65, 0xa4, 0x59, 0xf2, 0x10, - 0x1d, 0x50, 0xc6, 0x20, 0xb1, 0xee, 0x73, 0xdc, 0x39, 0xf2, 0x08, 0xdd, 0xe7, 0xc0, 0x22, 0x21, - 0xe1, 0xb3, 0xe4, 0x9b, 0x64, 0x03, 0xdd, 0x2e, 0x49, 0x93, 0xc0, 0x2d, 0xb2, 0x8a, 0xb0, 0x01, - 0xc9, 0xcf, 0x45, 0x11, 0xd9, 0x47, 0xdb, 0x17, 0x73, 0x4f, 0x12, 0xe6, 0xbd, 0x34, 0x97, 0x8a, - 0x74, 0x85, 0x80, 0x78, 0x61, 0x3a, 0x4c, 0x19, 0x53, 0xa9, 0xb4, 0x78, 0x91, 0xdc, 0x41, 0xbb, - 0x97, 0xe1, 0x24, 0x6d, 0x45, 0x82, 0x39, 0xdf, 0x17, 0xbc, 0x44, 0xf6, 0xd0, 0x56, 0xd9, 0x0f, - 0xa6, 0x38, 0x38, 0xca, 0x7b, 0xa0, 0xad, 0x30, 0x10, 0x83, 0xb4, 0x78, 0x99, 0x34, 0xd0, 0x5e, - 0x92, 0x9a, 0x8e, 0x93, 0xca, 0x8a, 0x23, 0xc1, 0xf2, 0x14, 0x1a, 0xda, 0xc2, 0x58, 0x9d, 0x4b, - 0x8e, 0xbd, 0x42, 0xff, 0xcf, 0x71, 0x1a, 0x4c, 0xa2, 0xa4, 0x01, 0xbc, 0x42, 0xb6, 0xd1, 0xc6, - 0x65, 0xf2, 0xcb, 0x14, 0x74, 0x1f, 0x13, 0x72, 0x0f, 0xd5, 0xaf, 0x00, 0xab, 0x14, 0xb7, 0x7d, - 0xd5, 0xd3, 0xee, 0xcb, 0xf4, 0xc3, 0xab, 0xbe, 0xa4, 0x69, 0x70, 0x71, 0x7c, 0xcd, 0x5b, 0x10, - 0x62, 0xf5, 0x42, 0x38, 0x0d, 0x85, 0xce, 0xeb, 0x64, 0x13, 0xad, 0xb5, 0xb5, 0x4a, 0x93, 0x4c, - 0x16, 0x27, 0x64, 0x4f, 0xd8, 0xbc, 0xba, 0x0d, 0xb2, 0x82, 0x16, 0xf3, 0x20, 0x07, 0x69, 0x85, - 0xed, 0xe3, 0x9a, 0x67, 0x33, 0x15, 0xc7, 0xa9, 0x14, 0xb6, 0xef, 0x38, 0x18, 0xa6, 0x45, 0x92, - 0xb1, 0x37, 0x49, 0x0d, 0xad, 0x56, 0xd0, 0x44, 0x9e, 0x2d, 0xff, 0xea, 0x0a, 0x09, 0xdd, 0x56, - 0xee, 0x85, 0x12, 0x12, 0x6f, 0x93, 0x65, 0x34, 0x9f, 0x08, 0x19, 0x6c, 0xbf, 0xe3, 0x67, 0x07, - 0xb8, 0xa8, 0x66, 0x67, 0xd7, 0xbf, 0xc4, 0x58, 0x6a, 0x53, 0x53, 0x8e, 0xce, 0x9e, 0xaf, 0x85, - 0x43, 0x04, 0x13, 0xf3, 0xb2, 0xef, 0x4d, 0x35, 0xcd, 0x33, 0xc5, 0xd5, 0xb8, 0x4e, 0xb6, 0xd0, - 0x3a, 0x95, 0x4a, 0xf6, 0x63, 0x95, 0x1a, 0x17, 0x83, 0xd5, 0x82, 0xb9, 0x16, 0xb5, 0xac, 0x83, - 0xef, 0x84, 0xa9, 0xca, 0x4a, 0xd6, 0x10, 0xab, 0x1e, 0x70, 0xdc, 0xf0, 0x5d, 0xab, 0xc2, 0xc5, - 0x55, 0xc6, 0x0b, 0xc8, 0xf1, 0x5d, 0x82, 0xd0, 0x6c, 0x8b, 0xb2, 0x6e, 0x9a, 0xe0, 0x7b, 0xc1, - 0x91, 0x5e, 0xd9, 0x9e, 0xaf, 0x94, 0x81, 0xb4, 0xa0, 0x73, 0xea, 0x57, 0xc1, 0x91, 0x17, 0xe1, - 0x7c, 0x1a, 0x81, 0xe3, 0x03, 0xef, 0xb8, 0xa9, 0x14, 0x2e, 0x4c, 0x2c, 0x8c, 0x01, 0x8e, 0xef, - 0x67, 0x4a, 0x78, 0x4e, 0x4b, 0xa9, 0x6e, 0x4c, 0x75, 0x17, 0x1f, 0x92, 0x75, 0x44, 0xf2, 0x17, - 0x46, 0x40, 0xb5, 0xeb, 0x08, 0x63, 0x95, 0xee, 0xe3, 0x07, 0x5e, 0xc6, 0x2c, 0x6e, 0xc0, 0x5a, - 0x21, 0xdb, 0xf8, 0x21, 0xa9, 0xa3, 0x9d, 0xaa, 0x11, 0x54, 0xb3, 0x8e, 0xe8, 0x81, 0x8b, 0x69, - 0x5b, 0x82, 0x8d, 0x84, 0xec, 0xe2, 0x47, 0xbe, 0x89, 0xd9, 0x99, 0x44, 0xab, 0x23, 0x11, 0x81, - 0x4b, 0x04, 0xb3, 0xa9, 0x06, 0xfc, 0xb5, 0x9f, 0xef, 0x0c, 0x79, 0x45, 0xa3, 0x08, 0x6c, 0x18, - 0xb5, 0x6f, 0x32, 0x4d, 0xf3, 0x8d, 0x52, 0x8e, 0x53, 0x69, 0xc8, 0xa6, 0x17, 0x4f, 0x83, 0xd5, - 0xf9, 0x8c, 0x9d, 0x07, 0x1f, 0x93, 0x03, 0xd4, 0xb8, 0xd2, 0x16, 0x95, 0x6b, 0xbf, 0xad, 0x3a, - 0x10, 0xc8, 0x45, 0x45, 0x06, 0x7f, 0xe7, 0x4b, 0x2a, 0x8f, 0x96, 0x37, 0xf4, 0x40, 0x07, 0xf7, - 0xe3, 0x27, 0xde, 0x14, 0x17, 0xde, 0x77, 0x8e, 0xf0, 0xd4, 0xa7, 0x28, 0x57, 0xd1, 0x54, 0xc6, - 0xf7, 0xc1, 0x1a, 0x56, 0xa7, 0xc6, 0x02, 0x77, 0xa9, 0x01, 0x8d, 0x7f, 0x08, 0x1d, 0x9f, 0x64, - 0x87, 0xfa, 0x7e, 0x0c, 0x1d, 0xbf, 0x50, 0xb9, 0xe3, 0xc0, 0x84, 0xf1, 0x89, 0x7f, 0xca, 0x77, - 0xd0, 0x14, 0x09, 0x22, 0xa0, 0x3d, 0xc0, 0x3f, 0x7b, 0x3c, 0x4b, 0x51, 0x38, 0xdd, 0x6f, 0xdd, - 0xb8, 0x32, 0xfc, 0x2f, 0xa1, 0xf5, 0x86, 0xf6, 0x80, 0x97, 0xcb, 0x19, 0x3f, 0xf3, 0xdb, 0xa4, - 0xca, 0xcb, 0xa8, 0x64, 0x10, 0x5d, 0x1a, 0xbc, 0x5f, 0xbd, 0x32, 0x05, 0x36, 0xb5, 0xee, 0xe7, - 0xa1, 0x6e, 0x1a, 0x45, 0xae, 0x0b, 0x7d, 0x46, 0x35, 0x37, 0xf8, 0xb7, 0x60, 0x85, 0x22, 0xe4, - 0x8a, 0x5d, 0xf2, 0x3b, 0xd9, 0x41, 0xb5, 0xfc, 0x39, 0x8a, 0x09, 0x1a, 0x39, 0xef, 0xa9, 0xe0, - 0xbe, 0x3f, 0x02, 0x0a, 0xd2, 0x64, 0x0a, 0x4a, 0x1a, 0x83, 0xe3, 0x60, 0xa9, 0x88, 0x30, 0x6d, - 0x2d, 0xfe, 0x39, 0xdf, 0x7c, 0xfc, 0xac, 0xfc, 0xed, 0x7d, 0x3d, 0x9b, 0xfd, 0xf7, 0xf4, 0xbf, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x3a, 0x4f, 0x6a, 0x93, 0x22, 0x08, 0x00, 0x00, + 0x17, 0x7e, 0x03, 0x79, 0x13, 0x50, 0x6e, 0x8a, 0xc8, 0xc5, 0xb9, 0x1b, 0x43, 0x43, 0x80, 0xd6, + 0xb4, 0xd0, 0x76, 0xda, 0x52, 0xda, 0xca, 0xd2, 0x89, 0x2d, 0xbc, 0x2b, 0x2d, 0x92, 0xd6, 0x1d, + 0xf7, 0x8b, 0xc6, 0x14, 0x97, 0xc9, 0x0c, 0x10, 0x0f, 0x31, 0x1f, 0xf2, 0x2b, 0xfb, 0x2b, 0xfa, + 0x3f, 0x3a, 0xda, 0x8b, 0xd6, 0x49, 0x9c, 0xf2, 0x29, 0xf1, 0x79, 0x1e, 0x1d, 0xe9, 0x3c, 0xe7, + 0x39, 0x67, 0x51, 0x63, 0x30, 0x1a, 0xbd, 0x3b, 0xf9, 0x73, 0x30, 0x3e, 0x39, 0xfd, 0xe0, 0xde, + 0x0f, 0xc7, 0x83, 0x37, 0x83, 0xf1, 0xc0, 0xbd, 0x1f, 0x9e, 0x9d, 0x0d, 0xde, 0x0e, 0x9b, 0xa3, + 0x8f, 0xa7, 0xe3, 0x53, 0x72, 0x2b, 0xfb, 0xf3, 0xfa, 0xd3, 0x5f, 0x8d, 0x7f, 0x56, 0xd0, 0x36, + 0xad, 0x0e, 0xc4, 0x05, 0x3f, 0xce, 0xe9, 0x64, 0x17, 0xdd, 0x3e, 0x3b, 0x79, 0xfb, 0x61, 0x30, + 0xfe, 0xf4, 0x71, 0x58, 0x9b, 0xa9, 0xcf, 0x1c, 0x2d, 0xea, 0x2a, 0x40, 0x6a, 0x68, 0x7e, 0x34, + 0x38, 0x7f, 0x77, 0x3a, 0x78, 0x53, 0xbb, 0x91, 0x61, 0xe5, 0x4f, 0xf2, 0x02, 0xcd, 0x8e, 0xcf, + 0x47, 0xc3, 0xda, 0xcd, 0xfa, 0xcc, 0xd1, 0xf2, 0xd3, 0x87, 0xcd, 0xf2, 0xbe, 0xe6, 0xf5, 0x77, + 0x35, 0xed, 0xf9, 0x68, 0xa8, 0xb3, 0x63, 0x8d, 0xbf, 0x97, 0xd1, 0xac, 0xff, 0x49, 0x16, 0xd0, + 0x7c, 0x2a, 0xbb, 0x52, 0xfd, 0x2e, 0xf1, 0xff, 0x08, 0x46, 0x8b, 0xac, 0x43, 0xad, 0x8b, 0xc1, + 0x18, 0xda, 0x06, 0x3c, 0x43, 0x08, 0x5a, 0x66, 0x4a, 0x5a, 0xca, 0xac, 0x4b, 0x13, 0x4e, 0x2d, + 0xe0, 0x1b, 0x64, 0x0f, 0x6d, 0xc5, 0x10, 0xb7, 0x40, 0x9b, 0x8e, 0x48, 0x8a, 0x70, 0x38, 0x72, + 0x93, 0xac, 0xa3, 0xd5, 0x84, 0x0a, 0xed, 0x84, 0x34, 0x96, 0x46, 0x11, 0xb5, 0x42, 0x49, 0x3c, + 0xeb, 0xc3, 0xa6, 0x2f, 0xd9, 0xc5, 0xf0, 0xff, 0xc9, 0x3d, 0x74, 0xa0, 0xe1, 0x55, 0x0a, 0xc6, + 0x3a, 0xca, 0xb9, 0x06, 0x63, 0xdc, 0xb1, 0xd2, 0xce, 0x6a, 0x2a, 0x0d, 0x65, 0x19, 0x69, 0x8e, + 0x3c, 0x42, 0x87, 0x94, 0x31, 0x48, 0xac, 0xfb, 0x1c, 0x77, 0x9e, 0x3c, 0x46, 0x0f, 0x38, 0xb0, + 0x48, 0x48, 0xf8, 0x2c, 0xf9, 0x16, 0xd9, 0x44, 0x77, 0x4a, 0xd2, 0x24, 0x70, 0x9b, 0xac, 0x21, + 0x6c, 0x40, 0xf2, 0x0b, 0x51, 0x44, 0x0e, 0xd0, 0xce, 0xe5, 0xdc, 0x93, 0x84, 0x05, 0x2f, 0xcd, + 0x95, 0x22, 0x5d, 0x21, 0x20, 0x5e, 0x9c, 0x0e, 0x53, 0xc6, 0x54, 0x2a, 0x2d, 0x5e, 0x22, 0x77, + 0xd1, 0xde, 0x55, 0x38, 0x49, 0x5b, 0x91, 0x60, 0xce, 0xf7, 0x05, 0x2f, 0x93, 0x7d, 0xb4, 0x5d, + 0xf6, 0x83, 0x29, 0x0e, 0x8e, 0xf2, 0x1e, 0x68, 0x2b, 0x0c, 0xc4, 0x20, 0x2d, 0x5e, 0x21, 0x0d, + 0xb4, 0x9f, 0xa4, 0xa6, 0xe3, 0xa4, 0xb2, 0xe2, 0x58, 0xb0, 0x3c, 0x85, 0x86, 0xb6, 0x30, 0x56, + 0xe7, 0x92, 0x63, 0xaf, 0xd0, 0x7f, 0x73, 0x9c, 0x06, 0x93, 0x28, 0x69, 0x00, 0xaf, 0x92, 0x1d, + 0xb4, 0x79, 0x95, 0xfc, 0x2a, 0x05, 0xdd, 0xc7, 0x84, 0xdc, 0x47, 0xf5, 0x6b, 0xc0, 0x2a, 0xc5, + 0x1d, 0x5f, 0xf5, 0xb4, 0xfb, 0x32, 0xfd, 0xf0, 0x9a, 0x2f, 0x69, 0x1a, 0x5c, 0x1c, 0x5f, 0xf7, + 0x16, 0x84, 0x58, 0xbd, 0x14, 0x4e, 0x43, 0xa1, 0xf3, 0x06, 0xd9, 0x42, 0xeb, 0x6d, 0xad, 0xd2, + 0x24, 0x93, 0xc5, 0x09, 0xd9, 0x13, 0x36, 0xaf, 0x6e, 0x93, 0xac, 0xa2, 0xa5, 0x3c, 0xc8, 0x41, + 0x5a, 0x61, 0xfb, 0xb8, 0xe6, 0xd9, 0x4c, 0xc5, 0x71, 0x2a, 0x85, 0xed, 0x3b, 0x0e, 0x86, 0x69, + 0x91, 0x64, 0xec, 0x2d, 0x52, 0x43, 0x6b, 0x15, 0x34, 0x91, 0x67, 0xdb, 0xbf, 0xba, 0x42, 0x42, + 0xb7, 0x95, 0x7b, 0xa9, 0x84, 0xc4, 0x3b, 0x64, 0x05, 0x2d, 0x24, 0x42, 0x06, 0xdb, 0xef, 0xfa, + 0xd9, 0x01, 0x2e, 0xaa, 0xd9, 0xd9, 0xf3, 0x2f, 0x31, 0x96, 0xda, 0xd4, 0x94, 0xa3, 0xb3, 0xef, + 0x6b, 0xe1, 0x10, 0xc1, 0xc4, 0xbc, 0x1c, 0x78, 0x53, 0x4d, 0xf3, 0x4c, 0x71, 0x35, 0xae, 0x93, + 0x6d, 0xb4, 0x41, 0xa5, 0x92, 0xfd, 0x58, 0xa5, 0xc6, 0xc5, 0x60, 0xb5, 0x60, 0xae, 0x45, 0x2d, + 0xeb, 0xe0, 0xbb, 0x61, 0xaa, 0xb2, 0x92, 0x35, 0xc4, 0xaa, 0x07, 0x1c, 0x37, 0x7c, 0xd7, 0xaa, + 0x70, 0x71, 0x95, 0xf1, 0x02, 0x72, 0x7c, 0x8f, 0x20, 0x34, 0xd7, 0xa2, 0xac, 0x9b, 0x26, 0xf8, + 0x7e, 0x70, 0xa4, 0x57, 0xb6, 0xe7, 0x2b, 0x65, 0x20, 0x2d, 0xe8, 0x9c, 0xfa, 0x45, 0x70, 0xe4, + 0x65, 0x38, 0x9f, 0x46, 0xe0, 0xf8, 0xd0, 0x3b, 0x6e, 0x2a, 0x85, 0x0b, 0x13, 0x0b, 0x63, 0x80, + 0xe3, 0x07, 0x99, 0x12, 0x9e, 0xd3, 0x52, 0xaa, 0x1b, 0x53, 0xdd, 0xc5, 0x47, 0x64, 0x03, 0x91, + 0xfc, 0x85, 0x11, 0x50, 0xed, 0x3a, 0xc2, 0x58, 0xa5, 0xfb, 0xf8, 0xa1, 0x97, 0x31, 0x8b, 0x1b, + 0xb0, 0x56, 0xc8, 0x36, 0x7e, 0x44, 0xea, 0x68, 0xb7, 0x6a, 0x04, 0xd5, 0xac, 0x23, 0x7a, 0xe0, + 0x62, 0xda, 0x96, 0x60, 0x23, 0x21, 0xbb, 0xf8, 0xb1, 0x6f, 0x62, 0x76, 0x26, 0xd1, 0xea, 0x58, + 0x44, 0xe0, 0x12, 0xc1, 0x6c, 0xaa, 0x01, 0x7f, 0x19, 0xb2, 0x95, 0x33, 0xf6, 0x55, 0x26, 0x66, + 0xbe, 0x4a, 0xca, 0x39, 0x2a, 0x9d, 0xd8, 0xf4, 0xaa, 0x69, 0xb0, 0x3a, 0x1f, 0xae, 0x8b, 0xe0, + 0x13, 0x72, 0x88, 0x1a, 0xd7, 0xfa, 0xa1, 0xb2, 0xeb, 0xd7, 0x95, 0xf4, 0x81, 0x5c, 0x94, 0x62, + 0xf0, 0x37, 0xbe, 0x96, 0xf2, 0x68, 0x79, 0x43, 0x0f, 0x74, 0xb0, 0x3d, 0x7e, 0xea, 0xdd, 0x70, + 0xe9, 0x7d, 0x17, 0x08, 0xcf, 0x7c, 0x8a, 0x72, 0x07, 0x4d, 0x65, 0x7c, 0x1b, 0x3c, 0x61, 0x75, + 0x6a, 0x2c, 0x70, 0x97, 0x1a, 0xd0, 0xf8, 0xbb, 0xd0, 0xea, 0x49, 0x76, 0xa8, 0xef, 0xfb, 0xd0, + 0xea, 0x4b, 0x95, 0x3b, 0x0e, 0x4c, 0x18, 0x9f, 0xf8, 0x87, 0x7c, 0xf9, 0x4c, 0x91, 0x20, 0x02, + 0xda, 0x03, 0xfc, 0xa3, 0xc7, 0xb3, 0x14, 0x85, 0xc5, 0xfd, 0xba, 0x8d, 0x2b, 0xa7, 0xff, 0x14, + 0x7a, 0x6e, 0x68, 0x0f, 0x78, 0xb9, 0x95, 0xf1, 0x73, 0xbf, 0x46, 0xaa, 0xbc, 0x8c, 0x4a, 0x06, + 0xd1, 0x95, 0x89, 0xfb, 0xd9, 0x2b, 0x53, 0x60, 0x53, 0xeb, 0x7e, 0x11, 0x9a, 0xdd, 0x85, 0xbe, + 0xff, 0x00, 0xe1, 0x5f, 0xfc, 0x7a, 0x2f, 0x23, 0x8c, 0x6a, 0xee, 0x8a, 0xfd, 0xf1, 0x2b, 0xd9, + 0x45, 0xb5, 0xfc, 0x25, 0x8a, 0x09, 0x1a, 0x39, 0xef, 0xa3, 0xe0, 0xb8, 0xdf, 0x02, 0x0a, 0xd2, + 0x64, 0xe2, 0x49, 0x1a, 0x83, 0xe3, 0x60, 0xa9, 0x88, 0x30, 0x0d, 0xf2, 0x1e, 0xa7, 0x51, 0x14, + 0xee, 0x6a, 0xb5, 0x96, 0xfe, 0x58, 0x68, 0x3e, 0x79, 0x5e, 0x7e, 0x86, 0x5f, 0xcf, 0x65, 0xff, + 0x3d, 0xfb, 0x37, 0x00, 0x00, 0xff, 0xff, 0xef, 0xbf, 0x60, 0xd4, 0x2d, 0x08, 0x00, 0x00, } diff --git a/protocol/protobuf/application_metadata_message.proto b/protocol/protobuf/application_metadata_message.proto index 0cedde848..371bee709 100644 --- a/protocol/protobuf/application_metadata_message.proto +++ b/protocol/protobuf/application_metadata_message.proto @@ -58,7 +58,7 @@ message ApplicationMetadataMessage { SYNC_SETTING = 42; COMMUNITY_ARCHIVE_MAGNETLINK = 43; SYNC_PROFILE_PICTURE = 44; - SYNC_WALLET_ACCOUNT = 45; + SYNC_ACCOUNT = 45; ACCEPT_CONTACT_REQUEST = 46; RETRACT_CONTACT_REQUEST = 47; COMMUNITY_REQUEST_TO_JOIN_RESPONSE = 48; @@ -74,9 +74,10 @@ message ApplicationMetadataMessage { SYNC_SAVED_ADDRESS = 59; COMMUNITY_CANCEL_REQUEST_TO_JOIN = 60; CANCEL_CONTACT_VERIFICATION = 61; - SYNC_ALL_KEYCARDS = 62; + SYNC_KEYPAIR = 62; SYNC_KEYCARD_ACTION = 63; SYNC_SOCIAL_LINK_SETTING = 64; SYNC_ENS_USERNAME_DETAIL = 65; + SYNC_FULL_KEYPAIR = 66; } } diff --git a/protocol/protobuf/pairing.pb.go b/protocol/protobuf/pairing.pb.go index 1c4855695..325cac91b 100644 --- a/protocol/protobuf/pairing.pb.go +++ b/protocol/protobuf/pairing.pb.go @@ -45,7 +45,7 @@ func (x SyncTrustedUser_TrustStatus) String() string { } func (SyncTrustedUser_TrustStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{27, 0} + return fileDescriptor_d61ab7221f0b5518, []int{28, 0} } type SyncVerificationRequest_VerificationStatus int32 @@ -79,7 +79,7 @@ func (x SyncVerificationRequest_VerificationStatus) String() string { } func (SyncVerificationRequest_VerificationStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{28, 0} + return fileDescriptor_d61ab7221f0b5518, []int{29, 0} } type SyncContactRequestDecision_DecisionStatus int32 @@ -104,7 +104,7 @@ func (x SyncContactRequestDecision_DecisionStatus) String() string { } func (SyncContactRequestDecision_DecisionStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{29, 0} + return fileDescriptor_d61ab7221f0b5518, []int{30, 0} } type SyncKeycardAction_Action int32 @@ -147,7 +147,7 @@ func (x SyncKeycardAction_Action) String() string { } func (SyncKeycardAction_Action) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{34, 0} + return fileDescriptor_d61ab7221f0b5518, []int{35, 0} } // `FetchingBackedUpDataDetails` is used to describe how many messages a single backup data structure consists of @@ -205,19 +205,19 @@ type Backup struct { Contacts []*SyncInstallationContactV2 `protobuf:"bytes,3,rep,name=contacts,proto3" json:"contacts,omitempty"` Communities []*SyncCommunity `protobuf:"bytes,4,rep,name=communities,proto3" json:"communities,omitempty"` // newly added details to be backed up to and fetched from waku - ContactsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,5,opt,name=contactsDetails,proto3" json:"contactsDetails,omitempty"` - CommunitiesDetails *FetchingBackedUpDataDetails `protobuf:"bytes,6,opt,name=communitiesDetails,proto3" json:"communitiesDetails,omitempty"` - Profile *BackedUpProfile `protobuf:"bytes,7,opt,name=profile,proto3" json:"profile,omitempty"` - ProfileDetails *FetchingBackedUpDataDetails `protobuf:"bytes,8,opt,name=profileDetails,proto3" json:"profileDetails,omitempty"` - Setting *SyncSetting `protobuf:"bytes,9,opt,name=setting,proto3" json:"setting,omitempty"` - SettingsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,10,opt,name=settingsDetails,proto3" json:"settingsDetails,omitempty"` - Keycards *SyncAllKeycards `protobuf:"bytes,11,opt,name=keycards,proto3" json:"keycards,omitempty"` - KeycardsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,12,opt,name=keycardsDetails,proto3" json:"keycardsDetails,omitempty"` - WalletAccount *SyncWalletAccount `protobuf:"bytes,13,opt,name=walletAccount,proto3" json:"walletAccount,omitempty"` - WalletAccountsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,14,opt,name=walletAccountsDetails,proto3" json:"walletAccountsDetails,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ContactsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,5,opt,name=contactsDetails,proto3" json:"contactsDetails,omitempty"` + CommunitiesDetails *FetchingBackedUpDataDetails `protobuf:"bytes,6,opt,name=communitiesDetails,proto3" json:"communitiesDetails,omitempty"` + Profile *BackedUpProfile `protobuf:"bytes,7,opt,name=profile,proto3" json:"profile,omitempty"` + ProfileDetails *FetchingBackedUpDataDetails `protobuf:"bytes,8,opt,name=profileDetails,proto3" json:"profileDetails,omitempty"` + Setting *SyncSetting `protobuf:"bytes,9,opt,name=setting,proto3" json:"setting,omitempty"` + SettingsDetails *FetchingBackedUpDataDetails `protobuf:"bytes,10,opt,name=settingsDetails,proto3" json:"settingsDetails,omitempty"` + FullKeypair *SyncKeypairFull `protobuf:"bytes,11,opt,name=fullKeypair,proto3" json:"fullKeypair,omitempty"` + FullKeypairDetails *FetchingBackedUpDataDetails `protobuf:"bytes,12,opt,name=fullKeypairDetails,proto3" json:"fullKeypairDetails,omitempty"` + WatchOnlyAccount *SyncAccount `protobuf:"bytes,13,opt,name=watchOnlyAccount,proto3" json:"watchOnlyAccount,omitempty"` + WatchOnlyAccountDetails *FetchingBackedUpDataDetails `protobuf:"bytes,14,opt,name=watchOnlyAccountDetails,proto3" json:"watchOnlyAccountDetails,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Backup) Reset() { *m = Backup{} } @@ -315,30 +315,30 @@ func (m *Backup) GetSettingsDetails() *FetchingBackedUpDataDetails { return nil } -func (m *Backup) GetKeycards() *SyncAllKeycards { +func (m *Backup) GetFullKeypair() *SyncKeypairFull { if m != nil { - return m.Keycards + return m.FullKeypair } return nil } -func (m *Backup) GetKeycardsDetails() *FetchingBackedUpDataDetails { +func (m *Backup) GetFullKeypairDetails() *FetchingBackedUpDataDetails { if m != nil { - return m.KeycardsDetails + return m.FullKeypairDetails } return nil } -func (m *Backup) GetWalletAccount() *SyncWalletAccount { +func (m *Backup) GetWatchOnlyAccount() *SyncAccount { if m != nil { - return m.WalletAccount + return m.WatchOnlyAccount } return nil } -func (m *Backup) GetWalletAccountsDetails() *FetchingBackedUpDataDetails { +func (m *Backup) GetWatchOnlyAccountDetails() *FetchingBackedUpDataDetails { if m != nil { - return m.WalletAccountsDetails + return m.WatchOnlyAccountDetails } return nil } @@ -2040,212 +2040,275 @@ func (m *SyncProfilePictures) GetPictures() []*SyncProfilePicture { return nil } -type SyncWalletAccount struct { - Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"` - Address []byte `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` - Wallet bool `protobuf:"varint,3,opt,name=wallet,proto3" json:"wallet,omitempty"` - Chat bool `protobuf:"varint,4,opt,name=chat,proto3" json:"chat,omitempty"` - Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"` - Storage string `protobuf:"bytes,6,opt,name=storage,proto3" json:"storage,omitempty"` - Path string `protobuf:"bytes,7,opt,name=path,proto3" json:"path,omitempty"` - PublicKey []byte `protobuf:"bytes,8,opt,name=publicKey,proto3" json:"publicKey,omitempty"` - Name string `protobuf:"bytes,9,opt,name=name,proto3" json:"name,omitempty"` - Color string `protobuf:"bytes,10,opt,name=color,proto3" json:"color,omitempty"` - Hidden bool `protobuf:"varint,11,opt,name=hidden,proto3" json:"hidden,omitempty"` - Removed bool `protobuf:"varint,12,opt,name=removed,proto3" json:"removed,omitempty"` - Emoji string `protobuf:"bytes,13,opt,name=emoji,proto3" json:"emoji,omitempty"` - DerivedFrom string `protobuf:"bytes,14,opt,name=derived_from,json=derivedFrom,proto3" json:"derived_from,omitempty"` - KeyUid string `protobuf:"bytes,15,opt,name=key_uid,json=keyUid,proto3" json:"key_uid,omitempty"` - KeypairName string `protobuf:"bytes,16,opt,name=keypair_name,json=keypairName,proto3" json:"keypair_name,omitempty"` - LastUsedDerivationIndex uint64 `protobuf:"varint,17,opt,name=last_used_derivation_index,json=lastUsedDerivationIndex,proto3" json:"last_used_derivation_index,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +type SyncAccount struct { + Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"` + Address []byte `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + KeyUid string `protobuf:"bytes,3,opt,name=key_uid,json=keyUid,proto3" json:"key_uid,omitempty"` + PublicKey []byte `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + Color string `protobuf:"bytes,7,opt,name=color,proto3" json:"color,omitempty"` + Emoji string `protobuf:"bytes,8,opt,name=emoji,proto3" json:"emoji,omitempty"` + Wallet bool `protobuf:"varint,9,opt,name=wallet,proto3" json:"wallet,omitempty"` + Chat bool `protobuf:"varint,10,opt,name=chat,proto3" json:"chat,omitempty"` + Hidden bool `protobuf:"varint,11,opt,name=hidden,proto3" json:"hidden,omitempty"` + Removed bool `protobuf:"varint,12,opt,name=removed,proto3" json:"removed,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *SyncWalletAccount) Reset() { *m = SyncWalletAccount{} } -func (m *SyncWalletAccount) String() string { return proto.CompactTextString(m) } -func (*SyncWalletAccount) ProtoMessage() {} -func (*SyncWalletAccount) Descriptor() ([]byte, []int) { +func (m *SyncAccount) Reset() { *m = SyncAccount{} } +func (m *SyncAccount) String() string { return proto.CompactTextString(m) } +func (*SyncAccount) ProtoMessage() {} +func (*SyncAccount) Descriptor() ([]byte, []int) { return fileDescriptor_d61ab7221f0b5518, []int{23} } -func (m *SyncWalletAccount) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SyncWalletAccount.Unmarshal(m, b) +func (m *SyncAccount) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SyncAccount.Unmarshal(m, b) } -func (m *SyncWalletAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SyncWalletAccount.Marshal(b, m, deterministic) +func (m *SyncAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SyncAccount.Marshal(b, m, deterministic) } -func (m *SyncWalletAccount) XXX_Merge(src proto.Message) { - xxx_messageInfo_SyncWalletAccount.Merge(m, src) +func (m *SyncAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_SyncAccount.Merge(m, src) } -func (m *SyncWalletAccount) XXX_Size() int { - return xxx_messageInfo_SyncWalletAccount.Size(m) +func (m *SyncAccount) XXX_Size() int { + return xxx_messageInfo_SyncAccount.Size(m) } -func (m *SyncWalletAccount) XXX_DiscardUnknown() { - xxx_messageInfo_SyncWalletAccount.DiscardUnknown(m) +func (m *SyncAccount) XXX_DiscardUnknown() { + xxx_messageInfo_SyncAccount.DiscardUnknown(m) } -var xxx_messageInfo_SyncWalletAccount proto.InternalMessageInfo +var xxx_messageInfo_SyncAccount proto.InternalMessageInfo -func (m *SyncWalletAccount) GetClock() uint64 { +func (m *SyncAccount) GetClock() uint64 { if m != nil { return m.Clock } return 0 } -func (m *SyncWalletAccount) GetAddress() []byte { +func (m *SyncAccount) GetAddress() []byte { if m != nil { return m.Address } return nil } -func (m *SyncWalletAccount) GetWallet() bool { - if m != nil { - return m.Wallet - } - return false -} - -func (m *SyncWalletAccount) GetChat() bool { - if m != nil { - return m.Chat - } - return false -} - -func (m *SyncWalletAccount) GetType() string { - if m != nil { - return m.Type - } - return "" -} - -func (m *SyncWalletAccount) GetStorage() string { - if m != nil { - return m.Storage - } - return "" -} - -func (m *SyncWalletAccount) GetPath() string { - if m != nil { - return m.Path - } - return "" -} - -func (m *SyncWalletAccount) GetPublicKey() []byte { - if m != nil { - return m.PublicKey - } - return nil -} - -func (m *SyncWalletAccount) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *SyncWalletAccount) GetColor() string { - if m != nil { - return m.Color - } - return "" -} - -func (m *SyncWalletAccount) GetHidden() bool { - if m != nil { - return m.Hidden - } - return false -} - -func (m *SyncWalletAccount) GetRemoved() bool { - if m != nil { - return m.Removed - } - return false -} - -func (m *SyncWalletAccount) GetEmoji() string { - if m != nil { - return m.Emoji - } - return "" -} - -func (m *SyncWalletAccount) GetDerivedFrom() string { - if m != nil { - return m.DerivedFrom - } - return "" -} - -func (m *SyncWalletAccount) GetKeyUid() string { +func (m *SyncAccount) GetKeyUid() string { if m != nil { return m.KeyUid } return "" } -func (m *SyncWalletAccount) GetKeypairName() string { +func (m *SyncAccount) GetPublicKey() []byte { if m != nil { - return m.KeypairName + return m.PublicKey + } + return nil +} + +func (m *SyncAccount) GetPath() string { + if m != nil { + return m.Path } return "" } -func (m *SyncWalletAccount) GetLastUsedDerivationIndex() uint64 { +func (m *SyncAccount) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *SyncAccount) GetColor() string { + if m != nil { + return m.Color + } + return "" +} + +func (m *SyncAccount) GetEmoji() string { + if m != nil { + return m.Emoji + } + return "" +} + +func (m *SyncAccount) GetWallet() bool { + if m != nil { + return m.Wallet + } + return false +} + +func (m *SyncAccount) GetChat() bool { + if m != nil { + return m.Chat + } + return false +} + +func (m *SyncAccount) GetHidden() bool { + if m != nil { + return m.Hidden + } + return false +} + +func (m *SyncAccount) GetRemoved() bool { + if m != nil { + return m.Removed + } + return false +} + +type SyncKeypair struct { + Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"` + KeyUid string `protobuf:"bytes,2,opt,name=key_uid,json=keyUid,proto3" json:"key_uid,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` + DerivedFrom string `protobuf:"bytes,5,opt,name=derived_from,json=derivedFrom,proto3" json:"derived_from,omitempty"` + LastUsedDerivationIndex uint64 `protobuf:"varint,6,opt,name=last_used_derivation_index,json=lastUsedDerivationIndex,proto3" json:"last_used_derivation_index,omitempty"` + SyncedFrom string `protobuf:"bytes,7,opt,name=synced_from,json=syncedFrom,proto3" json:"synced_from,omitempty"` + Accounts []*SyncAccount `protobuf:"bytes,8,rep,name=accounts,proto3" json:"accounts,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SyncKeypair) Reset() { *m = SyncKeypair{} } +func (m *SyncKeypair) String() string { return proto.CompactTextString(m) } +func (*SyncKeypair) ProtoMessage() {} +func (*SyncKeypair) Descriptor() ([]byte, []int) { + return fileDescriptor_d61ab7221f0b5518, []int{24} +} + +func (m *SyncKeypair) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SyncKeypair.Unmarshal(m, b) +} +func (m *SyncKeypair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SyncKeypair.Marshal(b, m, deterministic) +} +func (m *SyncKeypair) XXX_Merge(src proto.Message) { + xxx_messageInfo_SyncKeypair.Merge(m, src) +} +func (m *SyncKeypair) XXX_Size() int { + return xxx_messageInfo_SyncKeypair.Size(m) +} +func (m *SyncKeypair) XXX_DiscardUnknown() { + xxx_messageInfo_SyncKeypair.DiscardUnknown(m) +} + +var xxx_messageInfo_SyncKeypair proto.InternalMessageInfo + +func (m *SyncKeypair) GetClock() uint64 { + if m != nil { + return m.Clock + } + return 0 +} + +func (m *SyncKeypair) GetKeyUid() string { + if m != nil { + return m.KeyUid + } + return "" +} + +func (m *SyncKeypair) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *SyncKeypair) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *SyncKeypair) GetDerivedFrom() string { + if m != nil { + return m.DerivedFrom + } + return "" +} + +func (m *SyncKeypair) GetLastUsedDerivationIndex() uint64 { if m != nil { return m.LastUsedDerivationIndex } return 0 } -type SyncWalletAccounts struct { - Accounts []*SyncWalletAccount `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (m *SyncKeypair) GetSyncedFrom() string { + if m != nil { + return m.SyncedFrom + } + return "" } -func (m *SyncWalletAccounts) Reset() { *m = SyncWalletAccounts{} } -func (m *SyncWalletAccounts) String() string { return proto.CompactTextString(m) } -func (*SyncWalletAccounts) ProtoMessage() {} -func (*SyncWalletAccounts) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{24} -} - -func (m *SyncWalletAccounts) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SyncWalletAccounts.Unmarshal(m, b) -} -func (m *SyncWalletAccounts) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SyncWalletAccounts.Marshal(b, m, deterministic) -} -func (m *SyncWalletAccounts) XXX_Merge(src proto.Message) { - xxx_messageInfo_SyncWalletAccounts.Merge(m, src) -} -func (m *SyncWalletAccounts) XXX_Size() int { - return xxx_messageInfo_SyncWalletAccounts.Size(m) -} -func (m *SyncWalletAccounts) XXX_DiscardUnknown() { - xxx_messageInfo_SyncWalletAccounts.DiscardUnknown(m) -} - -var xxx_messageInfo_SyncWalletAccounts proto.InternalMessageInfo - -func (m *SyncWalletAccounts) GetAccounts() []*SyncWalletAccount { +func (m *SyncKeypair) GetAccounts() []*SyncAccount { if m != nil { return m.Accounts } return nil } +type SyncKeypairFull struct { + Keypair *SyncKeypair `protobuf:"bytes,1,opt,name=keypair,proto3" json:"keypair,omitempty"` + Keycards []*SyncKeycard `protobuf:"bytes,2,rep,name=keycards,proto3" json:"keycards,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SyncKeypairFull) Reset() { *m = SyncKeypairFull{} } +func (m *SyncKeypairFull) String() string { return proto.CompactTextString(m) } +func (*SyncKeypairFull) ProtoMessage() {} +func (*SyncKeypairFull) Descriptor() ([]byte, []int) { + return fileDescriptor_d61ab7221f0b5518, []int{25} +} + +func (m *SyncKeypairFull) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SyncKeypairFull.Unmarshal(m, b) +} +func (m *SyncKeypairFull) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SyncKeypairFull.Marshal(b, m, deterministic) +} +func (m *SyncKeypairFull) XXX_Merge(src proto.Message) { + xxx_messageInfo_SyncKeypairFull.Merge(m, src) +} +func (m *SyncKeypairFull) XXX_Size() int { + return xxx_messageInfo_SyncKeypairFull.Size(m) +} +func (m *SyncKeypairFull) XXX_DiscardUnknown() { + xxx_messageInfo_SyncKeypairFull.DiscardUnknown(m) +} + +var xxx_messageInfo_SyncKeypairFull proto.InternalMessageInfo + +func (m *SyncKeypairFull) GetKeypair() *SyncKeypair { + if m != nil { + return m.Keypair + } + return nil +} + +func (m *SyncKeypairFull) GetKeycards() []*SyncKeycard { + if m != nil { + return m.Keycards + } + return nil +} + type SyncSavedAddress struct { Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` @@ -2264,7 +2327,7 @@ func (m *SyncSavedAddress) Reset() { *m = SyncSavedAddress{} } func (m *SyncSavedAddress) String() string { return proto.CompactTextString(m) } func (*SyncSavedAddress) ProtoMessage() {} func (*SyncSavedAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{25} + return fileDescriptor_d61ab7221f0b5518, []int{26} } func (m *SyncSavedAddress) XXX_Unmarshal(b []byte) error { @@ -2354,7 +2417,7 @@ func (m *SyncCommunitySettings) Reset() { *m = SyncCommunitySettings{} } func (m *SyncCommunitySettings) String() string { return proto.CompactTextString(m) } func (*SyncCommunitySettings) ProtoMessage() {} func (*SyncCommunitySettings) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{26} + return fileDescriptor_d61ab7221f0b5518, []int{27} } func (m *SyncCommunitySettings) XXX_Unmarshal(b []byte) error { @@ -2409,7 +2472,7 @@ func (m *SyncTrustedUser) Reset() { *m = SyncTrustedUser{} } func (m *SyncTrustedUser) String() string { return proto.CompactTextString(m) } func (*SyncTrustedUser) ProtoMessage() {} func (*SyncTrustedUser) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{27} + return fileDescriptor_d61ab7221f0b5518, []int{28} } func (m *SyncTrustedUser) XXX_Unmarshal(b []byte) error { @@ -2470,7 +2533,7 @@ func (m *SyncVerificationRequest) Reset() { *m = SyncVerificationRequest func (m *SyncVerificationRequest) String() string { return proto.CompactTextString(m) } func (*SyncVerificationRequest) ProtoMessage() {} func (*SyncVerificationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{28} + return fileDescriptor_d61ab7221f0b5518, []int{29} } func (m *SyncVerificationRequest) XXX_Unmarshal(b []byte) error { @@ -2567,7 +2630,7 @@ func (m *SyncContactRequestDecision) Reset() { *m = SyncContactRequestDe func (m *SyncContactRequestDecision) String() string { return proto.CompactTextString(m) } func (*SyncContactRequestDecision) ProtoMessage() {} func (*SyncContactRequestDecision) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{29} + return fileDescriptor_d61ab7221f0b5518, []int{30} } func (m *SyncContactRequestDecision) XXX_Unmarshal(b []byte) error { @@ -2626,7 +2689,7 @@ func (m *BackedUpProfile) Reset() { *m = BackedUpProfile{} } func (m *BackedUpProfile) String() string { return proto.CompactTextString(m) } func (*BackedUpProfile) ProtoMessage() {} func (*BackedUpProfile) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{30} + return fileDescriptor_d61ab7221f0b5518, []int{31} } func (m *BackedUpProfile) XXX_Unmarshal(b []byte) error { @@ -2701,7 +2764,7 @@ func (m *RawMessage) Reset() { *m = RawMessage{} } func (m *RawMessage) String() string { return proto.CompactTextString(m) } func (*RawMessage) ProtoMessage() {} func (*RawMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{31} + return fileDescriptor_d61ab7221f0b5518, []int{32} } func (m *RawMessage) XXX_Unmarshal(b []byte) error { @@ -2750,7 +2813,7 @@ func (m *SyncRawMessage) Reset() { *m = SyncRawMessage{} } func (m *SyncRawMessage) String() string { return proto.CompactTextString(m) } func (*SyncRawMessage) ProtoMessage() {} func (*SyncRawMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{32} + return fileDescriptor_d61ab7221f0b5518, []int{33} } func (m *SyncRawMessage) XXX_Unmarshal(b []byte) error { @@ -2808,7 +2871,7 @@ func (m *SyncKeycard) Reset() { *m = SyncKeycard{} } func (m *SyncKeycard) String() string { return proto.CompactTextString(m) } func (*SyncKeycard) ProtoMessage() {} func (*SyncKeycard) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{33} + return fileDescriptor_d61ab7221f0b5518, []int{34} } func (m *SyncKeycard) XXX_Unmarshal(b []byte) error { @@ -2884,7 +2947,7 @@ 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{34} + return fileDescriptor_d61ab7221f0b5518, []int{35} } func (m *SyncKeycardAction) XXX_Unmarshal(b []byte) error { @@ -2926,53 +2989,6 @@ func (m *SyncKeycardAction) GetKeycard() *SyncKeycard { return nil } -type SyncAllKeycards struct { - Keycards []*SyncKeycard `protobuf:"bytes,1,rep,name=keycards,proto3" json:"keycards,omitempty"` - Clock uint64 `protobuf:"varint,2,opt,name=clock,proto3" json:"clock,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SyncAllKeycards) Reset() { *m = SyncAllKeycards{} } -func (m *SyncAllKeycards) String() string { return proto.CompactTextString(m) } -func (*SyncAllKeycards) ProtoMessage() {} -func (*SyncAllKeycards) Descriptor() ([]byte, []int) { - return fileDescriptor_d61ab7221f0b5518, []int{35} -} - -func (m *SyncAllKeycards) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SyncAllKeycards.Unmarshal(m, b) -} -func (m *SyncAllKeycards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SyncAllKeycards.Marshal(b, m, deterministic) -} -func (m *SyncAllKeycards) XXX_Merge(src proto.Message) { - xxx_messageInfo_SyncAllKeycards.Merge(m, src) -} -func (m *SyncAllKeycards) XXX_Size() int { - return xxx_messageInfo_SyncAllKeycards.Size(m) -} -func (m *SyncAllKeycards) XXX_DiscardUnknown() { - xxx_messageInfo_SyncAllKeycards.DiscardUnknown(m) -} - -var xxx_messageInfo_SyncAllKeycards proto.InternalMessageInfo - -func (m *SyncAllKeycards) GetKeycards() []*SyncKeycard { - if m != nil { - return m.Keycards - } - return nil -} - -func (m *SyncAllKeycards) GetClock() uint64 { - if m != nil { - return m.Clock - } - return 0 -} - type SyncSocialLinkSetting struct { Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` @@ -3060,8 +3076,9 @@ func init() { proto.RegisterType((*SyncClearHistory)(nil), "protobuf.SyncClearHistory") proto.RegisterType((*SyncProfilePicture)(nil), "protobuf.SyncProfilePicture") proto.RegisterType((*SyncProfilePictures)(nil), "protobuf.SyncProfilePictures") - proto.RegisterType((*SyncWalletAccount)(nil), "protobuf.SyncWalletAccount") - proto.RegisterType((*SyncWalletAccounts)(nil), "protobuf.SyncWalletAccounts") + proto.RegisterType((*SyncAccount)(nil), "protobuf.SyncAccount") + proto.RegisterType((*SyncKeypair)(nil), "protobuf.SyncKeypair") + proto.RegisterType((*SyncKeypairFull)(nil), "protobuf.SyncKeypairFull") proto.RegisterType((*SyncSavedAddress)(nil), "protobuf.SyncSavedAddress") proto.RegisterType((*SyncCommunitySettings)(nil), "protobuf.SyncCommunitySettings") proto.RegisterType((*SyncTrustedUser)(nil), "protobuf.SyncTrustedUser") @@ -3072,7 +3089,6 @@ func init() { proto.RegisterType((*SyncRawMessage)(nil), "protobuf.SyncRawMessage") proto.RegisterType((*SyncKeycard)(nil), "protobuf.SyncKeycard") proto.RegisterType((*SyncKeycardAction)(nil), "protobuf.SyncKeycardAction") - proto.RegisterType((*SyncAllKeycards)(nil), "protobuf.SyncAllKeycards") proto.RegisterType((*SyncSocialLinkSetting)(nil), "protobuf.SyncSocialLinkSetting") } @@ -3082,195 +3098,195 @@ func init() { var fileDescriptor_d61ab7221f0b5518 = []byte{ // 3049 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x39, 0x4b, 0x73, 0x1b, 0xc7, - 0xd1, 0xc6, 0x83, 0x78, 0x34, 0x40, 0x10, 0x1c, 0x51, 0x12, 0x44, 0xc9, 0x25, 0x69, 0x6d, 0x97, - 0xf5, 0x7d, 0xe5, 0x50, 0x89, 0x1c, 0xc7, 0x8e, 0x64, 0x97, 0x03, 0x01, 0xb0, 0x45, 0x51, 0x82, - 0x98, 0x21, 0x21, 0xc7, 0x4e, 0xaa, 0xb6, 0x56, 0xbb, 0x23, 0x62, 0x8c, 0xc5, 0x2e, 0xb2, 0x33, - 0xa0, 0x0c, 0x1f, 0x52, 0x49, 0x7e, 0x42, 0x2e, 0xc9, 0xd1, 0xe7, 0x1c, 0x53, 0x95, 0x43, 0x6e, - 0x39, 0xe6, 0x9e, 0xa3, 0x93, 0x3f, 0x90, 0xca, 0x0f, 0xc8, 0x31, 0x35, 0x3d, 0xb3, 0x8b, 0x5d, - 0x3c, 0x18, 0xb2, 0x72, 0xca, 0x09, 0xd3, 0xbd, 0xdd, 0x3d, 0x3d, 0xfd, 0x98, 0xee, 0x1e, 0xc0, - 0xe6, 0xc4, 0xe1, 0x11, 0x0f, 0x4e, 0xf6, 0x26, 0x51, 0x28, 0x43, 0x52, 0xc1, 0x9f, 0x17, 0xd3, - 0x97, 0xbb, 0x97, 0xc4, 0x2c, 0x70, 0x6d, 0xc1, 0xa4, 0xe4, 0xc1, 0x89, 0xd0, 0x9f, 0x77, 0x2d, - 0x67, 0x32, 0xf1, 0xb9, 0xeb, 0x48, 0x1e, 0x06, 0xf6, 0x98, 0x49, 0xc7, 0x73, 0xa4, 0x63, 0x8f, - 0x99, 0x10, 0xce, 0x09, 0xd3, 0x34, 0x96, 0x03, 0xd7, 0x3f, 0x61, 0xd2, 0x1d, 0xf2, 0xe0, 0xe4, - 0xa1, 0xe3, 0x8e, 0x98, 0x37, 0x98, 0x74, 0x1d, 0xe9, 0x74, 0x99, 0x74, 0xb8, 0x2f, 0xc8, 0x4d, - 0xa8, 0x21, 0x53, 0x30, 0x1d, 0xbf, 0x60, 0x51, 0x2b, 0x77, 0x2b, 0x77, 0x67, 0x93, 0x82, 0x42, - 0xf5, 0x11, 0x43, 0x6e, 0x43, 0x5d, 0x86, 0xd2, 0xf1, 0x63, 0x8a, 0x3c, 0x52, 0xd4, 0x10, 0xa7, - 0x49, 0xac, 0x5f, 0x96, 0xa1, 0xa4, 0x64, 0x4f, 0x27, 0x64, 0x07, 0x36, 0x5c, 0x3f, 0x74, 0x47, - 0x28, 0xa8, 0x48, 0x35, 0x40, 0x1a, 0x90, 0xe7, 0x1e, 0x72, 0x56, 0x69, 0x9e, 0x7b, 0xe4, 0x63, - 0xa8, 0xb8, 0x61, 0x20, 0x1d, 0x57, 0x8a, 0x56, 0xe1, 0x56, 0xe1, 0x4e, 0xed, 0xde, 0x1b, 0x7b, - 0xf1, 0x49, 0xf7, 0x8e, 0x66, 0x81, 0xbb, 0x1f, 0x08, 0xe9, 0xf8, 0x3e, 0x1e, 0xac, 0xa3, 0x29, - 0x9f, 0xdf, 0xa3, 0x09, 0x13, 0xf9, 0x21, 0xd4, 0xdc, 0x70, 0x3c, 0x9e, 0x06, 0x5c, 0x72, 0x26, - 0x5a, 0x45, 0x94, 0x71, 0x35, 0x2b, 0xa3, 0x63, 0x08, 0x66, 0x34, 0x4d, 0x4b, 0x9e, 0xc1, 0x56, - 0x2c, 0xc6, 0xd8, 0xa0, 0xb5, 0x71, 0x2b, 0x77, 0xa7, 0x76, 0xef, 0xad, 0x39, 0xfb, 0x19, 0x06, - 0xa3, 0x8b, 0xdc, 0x64, 0x00, 0x24, 0x25, 0x3f, 0x96, 0x59, 0xba, 0x88, 0xcc, 0x15, 0x02, 0xc8, - 0xbb, 0x50, 0x9e, 0x44, 0xe1, 0x4b, 0xee, 0xb3, 0x56, 0x19, 0x65, 0x5d, 0x9b, 0xcb, 0x8a, 0x65, - 0x1c, 0x6a, 0x02, 0x1a, 0x53, 0x92, 0xa7, 0xd0, 0x30, 0xcb, 0x58, 0x8f, 0xca, 0x45, 0xf4, 0x58, - 0x60, 0x26, 0x77, 0xa1, 0x6c, 0x22, 0xae, 0x55, 0x45, 0x39, 0x97, 0xb3, 0x26, 0x3e, 0xd2, 0x1f, - 0x69, 0x4c, 0xa5, 0x8c, 0x1b, 0x87, 0x68, 0xac, 0x00, 0x5c, 0xc8, 0xb8, 0x0b, 0xdc, 0xe4, 0x3d, - 0xa8, 0x8c, 0xd8, 0xcc, 0x75, 0x22, 0x4f, 0xb4, 0x6a, 0x8b, 0x66, 0x50, 0x2a, 0xb4, 0x7d, 0xff, - 0xc0, 0x10, 0xd0, 0x84, 0x54, 0xe9, 0x11, 0xaf, 0x63, 0x3d, 0xea, 0x17, 0xd2, 0x63, 0x81, 0x9b, - 0xb4, 0x61, 0xf3, 0x95, 0xe3, 0xfb, 0x4c, 0xb6, 0x5d, 0x37, 0x9c, 0x06, 0xb2, 0xb5, 0x89, 0xe2, - 0xae, 0x67, 0x95, 0xf9, 0x2c, 0x4d, 0x42, 0xb3, 0x1c, 0xe4, 0xa7, 0x70, 0x39, 0x83, 0x48, 0x34, - 0x6b, 0x5c, 0x44, 0xb3, 0xd5, 0x32, 0xac, 0x7f, 0x16, 0xa1, 0xfe, 0x74, 0xea, 0x4b, 0x1e, 0xef, - 0x46, 0xa0, 0x18, 0x38, 0x63, 0x86, 0x79, 0x58, 0xa5, 0xb8, 0x26, 0x37, 0xa0, 0x2a, 0xf9, 0x98, - 0x09, 0xe9, 0x8c, 0x27, 0x98, 0x8d, 0x05, 0x3a, 0x47, 0xa8, 0xaf, 0xdc, 0x63, 0x81, 0xe4, 0x6e, - 0x18, 0xb4, 0x0a, 0xc8, 0x36, 0x47, 0x90, 0x8f, 0x01, 0xdc, 0xd0, 0x0f, 0x23, 0x7b, 0xe8, 0x88, - 0xa1, 0x49, 0xb8, 0x5b, 0x73, 0x95, 0xd3, 0x7b, 0xef, 0x75, 0x14, 0xe1, 0x23, 0x47, 0x0c, 0x69, - 0xd5, 0x8d, 0x97, 0xe4, 0x9a, 0xca, 0x79, 0x25, 0x80, 0x7b, 0x98, 0x70, 0x05, 0x5a, 0x46, 0x78, - 0xdf, 0x23, 0x6f, 0x27, 0xde, 0xb2, 0xcd, 0xf5, 0x87, 0xe9, 0x53, 0xa5, 0x0d, 0x83, 0x3e, 0xd4, - 0x58, 0x72, 0x15, 0xca, 0x23, 0x36, 0xb3, 0xa7, 0xdc, 0xc3, 0x9c, 0xa8, 0xd2, 0xd2, 0x88, 0xcd, - 0x06, 0xdc, 0x23, 0x1f, 0x42, 0x89, 0x8f, 0x9d, 0x13, 0xa6, 0xe2, 0x5d, 0x69, 0xf6, 0xe6, 0x1a, - 0xcd, 0xf6, 0xf1, 0x3c, 0x72, 0xb6, 0xaf, 0x88, 0xa9, 0xe1, 0x21, 0x77, 0xe1, 0x92, 0x3b, 0x15, - 0x32, 0x1c, 0xf3, 0xaf, 0xf5, 0x55, 0x8a, 0x8a, 0x61, 0xc8, 0x57, 0x29, 0xc9, 0x7c, 0xc2, 0xa3, - 0xed, 0xde, 0x86, 0x6a, 0x72, 0x46, 0x75, 0xe5, 0xf1, 0xc0, 0x63, 0x5f, 0xb5, 0x72, 0xb7, 0x0a, - 0x77, 0x0a, 0x54, 0x03, 0xbb, 0xdf, 0xe6, 0x60, 0x33, 0xb3, 0x5b, 0x5a, 0xf9, 0x5c, 0x46, 0xf9, - 0xd8, 0x55, 0xf9, 0x94, 0xab, 0x5a, 0x50, 0x9e, 0x38, 0x33, 0x3f, 0x74, 0x3c, 0x74, 0x45, 0x9d, - 0xc6, 0xa0, 0xda, 0xee, 0x15, 0xf7, 0xa4, 0xf2, 0x81, 0x32, 0xa2, 0x06, 0xc8, 0x15, 0x28, 0x0d, - 0x19, 0x3f, 0x19, 0x4a, 0x63, 0x5b, 0x03, 0x91, 0x5d, 0xa8, 0xa8, 0x84, 0x16, 0xfc, 0x6b, 0x86, - 0x36, 0x2d, 0xd0, 0x04, 0x26, 0x6f, 0xc0, 0x66, 0x84, 0x2b, 0x5b, 0x3a, 0xd1, 0x09, 0x93, 0x68, - 0xd3, 0x02, 0xad, 0x6b, 0xe4, 0x31, 0xe2, 0xe6, 0x17, 0x7a, 0x25, 0x75, 0xa1, 0x5b, 0x7f, 0xcd, - 0xc1, 0xa5, 0x27, 0xa1, 0xeb, 0xf8, 0xc6, 0x33, 0x87, 0x46, 0xb9, 0xf7, 0xa0, 0x38, 0x62, 0x33, - 0x81, 0xa6, 0xa8, 0xdd, 0xbb, 0x3d, 0xf7, 0xc2, 0x0a, 0xe2, 0xbd, 0x03, 0x36, 0xa3, 0x48, 0x4e, - 0xee, 0x43, 0x7d, 0xac, 0xdc, 0xe4, 0x98, 0xe4, 0xca, 0x63, 0x46, 0x5c, 0x59, 0xed, 0x44, 0x9a, - 0xa1, 0x55, 0x27, 0x9c, 0x38, 0x42, 0xbc, 0x0a, 0x23, 0xcf, 0x44, 0x6d, 0x02, 0xef, 0x7e, 0x07, - 0x0a, 0x07, 0x6c, 0xb6, 0x32, 0x17, 0x08, 0x14, 0x55, 0x91, 0xc3, 0xad, 0xea, 0x14, 0xd7, 0xd6, - 0x9f, 0x72, 0x70, 0x39, 0xa3, 0x28, 0x63, 0xd1, 0x23, 0xe6, 0xfb, 0xa1, 0x8a, 0x50, 0x13, 0x99, - 0xf6, 0x29, 0x8b, 0x04, 0x0f, 0x03, 0x14, 0xb6, 0x41, 0x1b, 0x06, 0xfd, 0x5c, 0x63, 0x95, 0x93, - 0x27, 0x8c, 0x61, 0x90, 0x6b, 0xc9, 0x25, 0x05, 0xee, 0x7b, 0x58, 0x67, 0xd9, 0x29, 0x77, 0x99, - 0x8d, 0xaa, 0x68, 0x4d, 0x41, 0xa3, 0xfa, 0x4a, 0xa1, 0x39, 0x81, 0x9c, 0x4d, 0x18, 0x7a, 0x37, - 0x21, 0x38, 0x9e, 0x4d, 0x30, 0x7b, 0x05, 0x3f, 0x09, 0x1c, 0x39, 0x8d, 0x18, 0x7a, 0xb9, 0x4e, - 0xe7, 0x08, 0xeb, 0x9b, 0x1c, 0x34, 0x95, 0xda, 0xe9, 0xca, 0xb9, 0xa6, 0x1a, 0xbf, 0x0d, 0x5b, - 0x3c, 0x45, 0x65, 0x27, 0xa5, 0xb9, 0x91, 0x46, 0x67, 0x74, 0x46, 0x95, 0x0a, 0x4b, 0x2a, 0xc5, - 0x86, 0x2d, 0x66, 0x23, 0x37, 0x36, 0xd1, 0x06, 0xb6, 0x0a, 0x31, 0x68, 0xfd, 0x23, 0x07, 0x57, - 0xd7, 0x14, 0xf7, 0x73, 0xf6, 0x0d, 0x6f, 0xc0, 0xa6, 0xa9, 0x50, 0x36, 0xa6, 0xae, 0x51, 0xa9, - 0x6e, 0x90, 0x3a, 0xcf, 0xae, 0x41, 0x85, 0x05, 0xc2, 0x4e, 0x29, 0x56, 0x66, 0x81, 0x40, 0x1b, - 0xdf, 0x86, 0xba, 0xef, 0x08, 0x69, 0x4f, 0x27, 0x9e, 0x23, 0x99, 0xbe, 0x87, 0x8a, 0xb4, 0xa6, - 0x70, 0x03, 0x8d, 0x52, 0x67, 0x16, 0x33, 0x21, 0xd9, 0xd8, 0x96, 0xce, 0x89, 0x2a, 0xe3, 0x05, - 0x75, 0x66, 0x8d, 0x3a, 0x76, 0x4e, 0x04, 0x79, 0x0b, 0x1a, 0xbe, 0x8a, 0x11, 0x3b, 0xe0, 0xee, - 0x08, 0x37, 0xd1, 0x57, 0xd1, 0x26, 0x62, 0xfb, 0x06, 0x69, 0xfd, 0xaa, 0x04, 0xd7, 0xd6, 0x76, - 0x32, 0xe4, 0xbb, 0xb0, 0x93, 0x56, 0xc4, 0x46, 0x5e, 0x7f, 0x66, 0x4e, 0x4f, 0x52, 0x0a, 0x3d, - 0xd1, 0x5f, 0xfe, 0x87, 0x4d, 0xa1, 0x7c, 0xeb, 0x78, 0x1e, 0xf3, 0xf0, 0x42, 0xad, 0x50, 0x0d, - 0xa8, 0x38, 0x79, 0xa1, 0x9c, 0xcc, 0x3c, 0x6c, 0x11, 0x2a, 0x34, 0x06, 0x15, 0xfd, 0x78, 0xaa, - 0x74, 0xaa, 0x69, 0x7a, 0x04, 0x14, 0x7d, 0xc4, 0xc6, 0xe1, 0x29, 0xf3, 0xb0, 0x94, 0x57, 0x68, - 0x0c, 0x92, 0x5b, 0x50, 0x1f, 0x3a, 0xc2, 0x46, 0xb1, 0xf6, 0x54, 0x60, 0x69, 0xae, 0x50, 0x18, - 0x3a, 0xa2, 0xad, 0x50, 0x03, 0xbc, 0xe0, 0x4f, 0x59, 0xc4, 0x5f, 0xc6, 0xad, 0xb2, 0x90, 0x8e, - 0x9c, 0xea, 0xc2, 0x5b, 0xa0, 0x24, 0xfd, 0xe9, 0x08, 0xbf, 0x60, 0xd3, 0x1b, 0x4d, 0x85, 0x8c, - 0x29, 0xb7, 0x90, 0xb2, 0x86, 0x38, 0x43, 0xf2, 0x11, 0x5c, 0x37, 0x9d, 0xa0, 0x1d, 0xb1, 0x9f, - 0x4f, 0x99, 0x90, 0xda, 0x8b, 0xc8, 0xc2, 0x5a, 0x4d, 0xe4, 0x68, 0x19, 0x12, 0xaa, 0x29, 0xd0, - 0x99, 0x8a, 0x9f, 0xad, 0x67, 0xd7, 0x69, 0xb0, 0xbd, 0x96, 0xbd, 0x83, 0x99, 0xf1, 0x31, 0xdc, - 0x58, 0x64, 0x57, 0xe6, 0x90, 0xcc, 0x6c, 0x4f, 0x90, 0xff, 0x5a, 0x96, 0x9f, 0x22, 0x85, 0xde, - 0x7f, 0xbd, 0x00, 0xad, 0xc0, 0xa5, 0xf5, 0x02, 0xb4, 0x06, 0xb7, 0xa1, 0xee, 0x71, 0x31, 0xf1, - 0x9d, 0x99, 0x8e, 0xaf, 0x1d, 0x74, 0x7d, 0xcd, 0xe0, 0x54, 0x8c, 0x59, 0xaf, 0x96, 0xf3, 0x3d, - 0x6e, 0x4f, 0x56, 0xe7, 0xfb, 0x52, 0x50, 0xe7, 0x57, 0x04, 0xf5, 0x62, 0xe4, 0x16, 0x96, 0x22, - 0xd7, 0x7a, 0x08, 0xbb, 0x8b, 0x1b, 0x1f, 0x4e, 0x5f, 0xf8, 0xdc, 0xed, 0x0c, 0x9d, 0x73, 0xde, - 0x35, 0xd6, 0x1f, 0x0b, 0xb0, 0x99, 0x19, 0x23, 0xfe, 0x23, 0x5f, 0x1d, 0x13, 0xf3, 0x26, 0xd4, - 0x26, 0x11, 0x3f, 0x75, 0x24, 0xb3, 0x47, 0x6c, 0x66, 0xaa, 0x37, 0x18, 0x94, 0xaa, 0x46, 0xb7, - 0xd4, 0xad, 0x2a, 0xdc, 0x88, 0x4f, 0x94, 0x5e, 0x98, 0x97, 0x75, 0x9a, 0x46, 0xa9, 0x62, 0xfe, - 0x65, 0xc8, 0x03, 0x93, 0x95, 0x15, 0x6a, 0x20, 0x55, 0xea, 0x74, 0xac, 0x32, 0x0f, 0x8b, 0x79, - 0x85, 0x26, 0xf0, 0x3c, 0x69, 0xca, 0xe9, 0xa4, 0x79, 0x06, 0x4d, 0xe3, 0x5d, 0x61, 0xcb, 0xd0, - 0x56, 0x72, 0x4c, 0x87, 0xf4, 0xd6, 0xba, 0x61, 0xc9, 0x90, 0x1f, 0x87, 0x8f, 0x43, 0x1e, 0xd0, - 0x46, 0x94, 0x81, 0xc9, 0x03, 0xa8, 0xc4, 0x2d, 0xba, 0x19, 0x09, 0x6e, 0xae, 0x11, 0x64, 0x66, - 0x03, 0x41, 0x13, 0x06, 0x55, 0xc1, 0x58, 0xe0, 0x46, 0xb3, 0x89, 0x4c, 0x92, 0x7e, 0x8e, 0xc0, - 0xfa, 0x36, 0x61, 0xae, 0x74, 0xe6, 0xa9, 0x3f, 0x47, 0xa8, 0xa2, 0x65, 0x48, 0x55, 0x02, 0x63, - 0x93, 0x51, 0x47, 0xcb, 0x35, 0xe6, 0xe8, 0x03, 0x36, 0x13, 0xd6, 0xaf, 0x0b, 0x70, 0xfd, 0x8c, - 0x13, 0x19, 0x7f, 0xe5, 0x12, 0x7f, 0xbd, 0x0e, 0x30, 0xc1, 0xd8, 0x40, 0x77, 0x69, 0xff, 0x57, - 0x35, 0x46, 0x79, 0x2b, 0x71, 0x7a, 0x21, 0xed, 0xf4, 0x33, 0x2e, 0xd6, 0xab, 0x50, 0x76, 0x87, - 0x8e, 0x8c, 0xdb, 0xdc, 0x2a, 0x2d, 0x29, 0x70, 0xdf, 0x53, 0x71, 0x1b, 0x8f, 0x79, 0x33, 0xf5, - 0xb5, 0xa4, 0x1d, 0x9f, 0xe0, 0xf6, 0xd1, 0x89, 0x3a, 0x7d, 0xcb, 0x7a, 0x33, 0x04, 0xc8, 0x08, - 0x48, 0xc4, 0x4e, 0x99, 0xe3, 0x33, 0x4f, 0x5d, 0x72, 0x11, 0x13, 0x22, 0x69, 0x74, 0x3f, 0x3c, - 0x97, 0x1b, 0xf7, 0xa8, 0xe1, 0x6f, 0xc7, 0xec, 0xbd, 0x40, 0x46, 0x33, 0xba, 0x1d, 0x2d, 0xe2, - 0x77, 0xbb, 0x70, 0x65, 0x35, 0x31, 0x69, 0x42, 0x41, 0x59, 0x48, 0x37, 0x51, 0x6a, 0xa9, 0xd4, - 0x3d, 0x75, 0xfc, 0x29, 0x33, 0xd1, 0xaf, 0x81, 0xfb, 0xf9, 0x0f, 0x72, 0xd6, 0x6f, 0xf2, 0xd0, - 0x5c, 0xcc, 0x40, 0xf2, 0x51, 0x6a, 0xea, 0x5f, 0x6a, 0x10, 0xd7, 0xd4, 0xca, 0xd4, 0xcc, 0xff, - 0x29, 0xd4, 0x8d, 0xa3, 0x94, 0x41, 0x45, 0x2b, 0xbf, 0xd8, 0xe9, 0xaf, 0x4f, 0x79, 0x5a, 0x9b, - 0x24, 0x6b, 0x41, 0x1e, 0x40, 0x39, 0x6e, 0x34, 0x0b, 0x18, 0xc2, 0x67, 0xa8, 0x11, 0xf7, 0x9c, - 0x31, 0xc7, 0x7f, 0xf1, 0xf2, 0x60, 0xbd, 0x0f, 0x5b, 0xf8, 0x55, 0x29, 0x64, 0x4a, 0xd7, 0xf9, - 0xae, 0xa2, 0x0f, 0x61, 0x27, 0x66, 0x7c, 0xaa, 0xdf, 0x76, 0x04, 0x65, 0xce, 0x79, 0xb9, 0x7f, - 0x04, 0x57, 0x70, 0x50, 0x76, 0x25, 0x3f, 0xe5, 0x72, 0xd6, 0x61, 0x81, 0x64, 0xd1, 0x19, 0xfc, - 0x4d, 0x28, 0x70, 0x4f, 0x9b, 0xb7, 0x4e, 0xd5, 0xd2, 0xea, 0xea, 0xeb, 0x34, 0x2b, 0xa1, 0xed, - 0xba, 0x0c, 0xf3, 0xf6, 0xbc, 0x52, 0x7a, 0x3a, 0x2f, 0xb3, 0x52, 0xba, 0x5c, 0x8c, 0xb9, 0x10, - 0x17, 0x10, 0xf3, 0x4d, 0x0e, 0xea, 0x4a, 0xce, 0xc3, 0x30, 0x1c, 0x8d, 0x9d, 0x68, 0xb4, 0x9e, - 0x71, 0x1a, 0xf9, 0xc6, 0x0c, 0x6a, 0x99, 0x34, 0xab, 0x85, 0x54, 0xb3, 0x7a, 0x1d, 0xaa, 0x58, - 0x68, 0x6c, 0x45, 0xab, 0x13, 0xb9, 0x82, 0x88, 0x41, 0xe4, 0xa7, 0x3b, 0x8e, 0x8d, 0x6c, 0xc7, - 0xf1, 0x3a, 0x80, 0xc7, 0x7c, 0xa6, 0x3a, 0x37, 0x47, 0x62, 0x22, 0x17, 0x69, 0xd5, 0x60, 0xda, - 0xd2, 0xfa, 0x05, 0x5c, 0x56, 0x1a, 0xf6, 0x02, 0x31, 0x10, 0x2c, 0x52, 0x1b, 0xe9, 0x31, 0x7d, - 0x8d, 0xaa, 0xbb, 0x50, 0x99, 0x1a, 0x3a, 0xa3, 0x6f, 0x02, 0xe3, 0xd4, 0x3c, 0x74, 0x38, 0x36, - 0xe9, 0xfa, 0x06, 0x2a, 0x23, 0xbc, 0x9f, 0x69, 0x88, 0x8a, 0x19, 0xf5, 0xac, 0xc7, 0x3a, 0xf9, - 0x3a, 0x3e, 0x73, 0xa2, 0x47, 0x5c, 0xc8, 0x30, 0x9a, 0xa5, 0xaf, 0xa5, 0x5c, 0xe6, 0x5a, 0x7a, - 0x1d, 0xc0, 0x55, 0x84, 0xfa, 0x2c, 0x79, 0x7d, 0x16, 0x83, 0x69, 0x4b, 0xeb, 0x2f, 0x39, 0x20, - 0x4a, 0x98, 0x79, 0x6a, 0x3a, 0xe4, 0xae, 0x1a, 0x37, 0x56, 0x8e, 0x54, 0xa9, 0x99, 0x35, 0xbf, - 0x66, 0x66, 0x2d, 0xe0, 0x44, 0xb0, 0x34, 0xb3, 0x16, 0x11, 0x1d, 0xcf, 0xac, 0xd7, 0xa1, 0x8a, - 0x2d, 0x00, 0x0e, 0xad, 0x7a, 0x86, 0xc0, 0xa1, 0xf5, 0x68, 0xe5, 0xd0, 0x5a, 0x42, 0x82, 0x35, - 0x43, 0x6b, 0x39, 0x3d, 0xb4, 0x0e, 0xe1, 0xd2, 0xf2, 0x49, 0xc4, 0xfa, 0xb9, 0xfc, 0x03, 0xa8, - 0x4c, 0x0c, 0x91, 0xb9, 0x6c, 0x6e, 0x64, 0xf3, 0x3c, 0x2b, 0x89, 0x26, 0xd4, 0xd6, 0xdf, 0x0b, - 0xb0, 0xbd, 0xf4, 0x1e, 0xb4, 0xc6, 0xfb, 0x2d, 0x28, 0x9b, 0x4b, 0x3d, 0xb6, 0x9a, 0x01, 0x95, - 0x7d, 0xf4, 0x63, 0x0f, 0x9a, 0xad, 0x42, 0x0d, 0xa4, 0x6c, 0xaf, 0x7c, 0x67, 0xbc, 0x8e, 0x6b, - 0x85, 0xc3, 0x19, 0x4d, 0x97, 0x1c, 0x5c, 0x2b, 0xc9, 0xca, 0xf7, 0xaa, 0x8f, 0xd2, 0xcf, 0x29, - 0x31, 0xa8, 0xa8, 0x27, 0x8e, 0x1c, 0x9a, 0x76, 0x1d, 0xd7, 0xaa, 0xfc, 0x26, 0x55, 0x0f, 0x87, - 0xfd, 0x7a, 0xba, 0x0c, 0xc6, 0xfe, 0xae, 0xa6, 0xfc, 0xad, 0xce, 0x83, 0x0f, 0x25, 0x80, 0x48, - 0x0d, 0xa0, 0x57, 0xb9, 0xe7, 0xb1, 0xc0, 0xd4, 0x70, 0x03, 0x9d, 0xd1, 0xbf, 0xef, 0xc0, 0x06, - 0x1b, 0x87, 0x5f, 0x72, 0x6c, 0xdc, 0xab, 0x54, 0x03, 0xd8, 0x5f, 0xb2, 0x88, 0x9f, 0x32, 0xcf, - 0x7e, 0x19, 0x85, 0x63, 0x6c, 0xd6, 0x55, 0x7f, 0xa9, 0x71, 0x9f, 0x44, 0xe1, 0x38, 0xed, 0xb9, - 0xad, 0x8c, 0xe7, 0x6e, 0x43, 0x7d, 0xc4, 0x66, 0x6a, 0x34, 0xd7, 0x25, 0xba, 0xa9, 0x79, 0x0d, - 0x0e, 0xcb, 0xf4, 0x03, 0xd8, 0xd5, 0x5d, 0xa4, 0x60, 0x9e, 0x8d, 0x42, 0xcd, 0x30, 0x8c, 0x4f, - 0x39, 0xdb, 0xe8, 0xa1, 0xab, 0xd8, 0x53, 0x0a, 0xe6, 0x75, 0x93, 0xef, 0xfb, 0xea, 0xb3, 0xf5, - 0x54, 0xe7, 0x44, 0xc6, 0xbd, 0x82, 0xbc, 0x0f, 0x15, 0x53, 0x25, 0xe2, 0xfa, 0x76, 0xe6, 0xf3, - 0x60, 0x42, 0x6c, 0xfd, 0x2b, 0xa7, 0x13, 0xf6, 0xc8, 0x39, 0x4d, 0xaa, 0x6e, 0x3a, 0x2e, 0x72, - 0xd9, 0xb8, 0x58, 0xf5, 0x5e, 0x74, 0x03, 0xaa, 0x2f, 0x9d, 0xd3, 0x70, 0x1a, 0x71, 0xc9, 0x4c, - 0xb8, 0xcc, 0x11, 0x67, 0xdc, 0x64, 0xb7, 0xa1, 0xae, 0xfb, 0x68, 0x3b, 0x9d, 0x30, 0x35, 0x8d, - 0xd3, 0x8d, 0xfe, 0xff, 0xc3, 0xb6, 0xbe, 0x82, 0xc4, 0x30, 0x8c, 0x24, 0x1a, 0x54, 0x3f, 0x2b, - 0x57, 0xe9, 0x16, 0x7e, 0x38, 0x52, 0x78, 0x65, 0x54, 0xa1, 0x6e, 0x5d, 0x16, 0x08, 0x13, 0x25, - 0x6a, 0xa9, 0x7c, 0xc4, 0x85, 0x2d, 0x99, 0x90, 0xa6, 0xe3, 0x2b, 0x71, 0x71, 0xcc, 0x84, 0x7c, - 0x5c, 0xac, 0x14, 0x9b, 0x1b, 0xd6, 0x6f, 0x73, 0xfa, 0xae, 0x5c, 0x6a, 0x1b, 0xd7, 0x64, 0xcb, - 0x62, 0x13, 0xa5, 0x6d, 0x90, 0x69, 0xa2, 0x7a, 0x70, 0x73, 0xa8, 0x2f, 0x3d, 0xdb, 0x89, 0xdc, - 0x21, 0x3f, 0x65, 0xb6, 0x98, 0x4e, 0x26, 0x4a, 0x77, 0x16, 0x38, 0x2f, 0x7c, 0x33, 0x32, 0x54, - 0xe8, 0x0d, 0x43, 0xd6, 0xd6, 0x54, 0x47, 0x9a, 0xa8, 0xa7, 0x69, 0xac, 0x3f, 0xe4, 0x74, 0xb9, - 0x3e, 0x56, 0x33, 0x9f, 0x9a, 0x22, 0x59, 0x74, 0xce, 0x57, 0x8a, 0x8f, 0xa0, 0x64, 0xc6, 0x46, - 0xb5, 0x4f, 0x63, 0xb1, 0xd5, 0x4e, 0x09, 0xdc, 0x3b, 0x9e, 0x0f, 0x94, 0xd4, 0x30, 0x59, 0xf7, - 0xa1, 0x96, 0x42, 0x93, 0x1a, 0x94, 0x07, 0xfd, 0x83, 0xfe, 0xb3, 0xcf, 0xfa, 0xcd, 0xd7, 0x14, - 0x70, 0x4c, 0x07, 0x47, 0xc7, 0xbd, 0x6e, 0x33, 0x47, 0xb6, 0x61, 0x73, 0xd0, 0x47, 0xf0, 0xb3, - 0x67, 0xf4, 0xf8, 0xd1, 0xe7, 0xcd, 0xbc, 0xf5, 0x4d, 0x41, 0x8f, 0x5c, 0xcf, 0x53, 0x23, 0xad, - 0x69, 0x05, 0xd7, 0x28, 0x4f, 0xa0, 0x88, 0xe9, 0x65, 0x82, 0x49, 0xad, 0xd5, 0x81, 0x64, 0x68, - 0xea, 0x64, 0x5e, 0x86, 0x2a, 0xb8, 0xdc, 0xa1, 0x8a, 0xdd, 0xe0, 0x24, 0x6e, 0x77, 0xe7, 0x08, - 0xe5, 0x12, 0x33, 0x24, 0xe8, 0x12, 0x62, 0x5e, 0x12, 0x12, 0x5c, 0x1b, 0xdf, 0xe8, 0x22, 0x26, - 0x26, 0x61, 0x20, 0xe2, 0xab, 0x28, 0x81, 0x55, 0xfd, 0x89, 0xd8, 0xc4, 0xe7, 0x9a, 0x59, 0xc7, - 0x5f, 0xd5, 0x60, 0xda, 0x92, 0xb0, 0xd5, 0xa3, 0x7b, 0x05, 0x2d, 0xfb, 0xfd, 0xac, 0x65, 0x57, - 0x9c, 0x7a, 0xef, 0xf9, 0xd2, 0x70, 0xbf, 0x72, 0xe0, 0xd7, 0x3e, 0xac, 0x26, 0x4d, 0xd3, 0x4f, - 0x80, 0x2c, 0x73, 0x2e, 0xf9, 0xe2, 0xb0, 0xd7, 0xef, 0xee, 0xf7, 0x3f, 0x6d, 0xe6, 0x48, 0x1d, - 0x2a, 0xed, 0x4e, 0xa7, 0x77, 0xa8, 0x3c, 0x93, 0x57, 0x50, 0xb7, 0xd7, 0x79, 0xb2, 0xdf, 0xef, - 0x75, 0x9b, 0x05, 0x05, 0x75, 0xda, 0xfd, 0x4e, 0xef, 0x49, 0xaf, 0xdb, 0x2c, 0x5a, 0x7f, 0xcb, - 0xe9, 0x6e, 0xaa, 0x93, 0x99, 0xac, 0xbb, 0xcc, 0xe5, 0x62, 0xfd, 0x93, 0xdd, 0x0d, 0xa8, 0x1a, - 0x7b, 0xee, 0xc7, 0x91, 0x36, 0x47, 0x90, 0x9f, 0xc1, 0x96, 0x67, 0xf8, 0xed, 0x4c, 0xe4, 0xbd, - 0xbb, 0xd8, 0x97, 0xae, 0xda, 0x72, 0x2f, 0x5e, 0x18, 0xf3, 0x34, 0xbc, 0x0c, 0x6c, 0xbd, 0x03, - 0x8d, 0x2c, 0x45, 0xe6, 0xb0, 0xaf, 0x65, 0x0e, 0x9b, 0xb3, 0xbe, 0xcd, 0xc3, 0xd6, 0xc2, 0xdf, - 0x53, 0xeb, 0x2b, 0xec, 0xe2, 0x1b, 0x42, 0x7e, 0xe9, 0x0d, 0x81, 0xbc, 0x03, 0x24, 0x4d, 0x62, - 0xa7, 0x87, 0xb1, 0x66, 0x8a, 0x50, 0xdf, 0x55, 0xe9, 0x92, 0x5d, 0xbc, 0x48, 0xc9, 0x26, 0x3f, - 0x86, 0x1d, 0x11, 0xba, 0xdc, 0xf1, 0x6d, 0x9f, 0x07, 0xa3, 0xe4, 0x8f, 0xd6, 0xd6, 0x06, 0x4a, - 0x59, 0x18, 0x72, 0x8f, 0x90, 0xf2, 0x09, 0x0f, 0x46, 0xf1, 0x3f, 0x60, 0x44, 0x2c, 0xa2, 0x50, - 0xa4, 0x1a, 0x12, 0xe3, 0x5e, 0xce, 0xf6, 0x92, 0xbf, 0x06, 0x57, 0x88, 0x5c, 0x6a, 0x16, 0x29, - 0x61, 0x8b, 0x28, 0x61, 0x09, 0x00, 0xea, 0xbc, 0x32, 0x43, 0x40, 0xba, 0xe1, 0xca, 0x65, 0x1b, - 0xae, 0x03, 0xa8, 0x99, 0x7f, 0x81, 0x8f, 0x55, 0x57, 0x90, 0xc7, 0x68, 0xf8, 0xbf, 0xf9, 0x8e, - 0xed, 0xf9, 0xff, 0xc6, 0x4f, 0xcd, 0xdf, 0xc6, 0x46, 0xe8, 0x9e, 0x62, 0xa0, 0x69, 0x6e, 0xeb, - 0xf7, 0x39, 0x68, 0x28, 0x15, 0x53, 0x3b, 0xff, 0x00, 0x6a, 0x51, 0x02, 0xc5, 0xd5, 0x6e, 0x67, - 0x2e, 0x7f, 0x4e, 0x4a, 0xd3, 0x84, 0xe4, 0x1e, 0xec, 0x88, 0xe9, 0x8b, 0xb8, 0x62, 0x3e, 0x16, - 0x61, 0xf0, 0x70, 0x26, 0x59, 0xdc, 0xf9, 0xac, 0xfc, 0x46, 0xde, 0x81, 0xed, 0xd8, 0x1b, 0x73, - 0x06, 0xfd, 0xac, 0xb2, 0xfc, 0xc1, 0xfa, 0x5d, 0x0e, 0x6a, 0x4a, 0x59, 0xf3, 0xa7, 0x20, 0xce, - 0x01, 0x49, 0xdc, 0xa9, 0xe5, 0xca, 0xf2, 0x79, 0x05, 0x4a, 0xe6, 0x2d, 0xd2, 0xb4, 0x5a, 0xe6, - 0x29, 0x32, 0x15, 0xb9, 0xc5, 0x4c, 0xe4, 0xde, 0x80, 0xea, 0x7c, 0x14, 0xdf, 0xc0, 0xe9, 0x64, - 0x8e, 0x98, 0x27, 0x71, 0x29, 0xdd, 0x7f, 0xfe, 0x39, 0xaf, 0xbb, 0x42, 0xa3, 0x9a, 0x1a, 0x84, - 0xc2, 0x80, 0xdc, 0x87, 0x92, 0x83, 0x2b, 0xd4, 0xb1, 0x71, 0xcf, 0xca, 0xc6, 0x45, 0x86, 0x78, - 0x4f, 0xff, 0x50, 0xc3, 0x41, 0xde, 0x84, 0xcd, 0xd0, 0xf7, 0x0c, 0xc9, 0x20, 0x29, 0x42, 0x59, - 0x24, 0xb9, 0x8b, 0x87, 0x50, 0x90, 0x99, 0x77, 0x2f, 0xaf, 0xdc, 0x82, 0xc6, 0x54, 0xaa, 0x28, - 0x97, 0x8c, 0x76, 0xdb, 0xb0, 0x79, 0xd0, 0xfb, 0xbc, 0xd3, 0xa6, 0x5d, 0xbb, 0xdd, 0xed, 0x62, - 0xbe, 0x13, 0x68, 0xb4, 0x3b, 0x9d, 0x67, 0x83, 0xfe, 0xf1, 0x91, 0xc1, 0xe5, 0xc8, 0x25, 0xd8, - 0x8a, 0xc9, 0xba, 0xbd, 0x27, 0x3d, 0x7d, 0x0b, 0xee, 0x40, 0x33, 0x21, 0xa4, 0xbd, 0xa7, 0xcf, - 0x9e, 0xe3, 0x6d, 0x08, 0x50, 0x7a, 0xf2, 0xac, 0x73, 0xa0, 0xee, 0x42, 0x75, 0x75, 0x0c, 0xfa, - 0x06, 0xda, 0x20, 0x5b, 0x50, 0x1b, 0xec, 0x77, 0xed, 0xc1, 0x61, 0xb7, 0xad, 0x04, 0x94, 0x48, - 0x13, 0xea, 0xfd, 0xf6, 0xd3, 0x9e, 0xdd, 0x79, 0xd4, 0xee, 0x7f, 0xda, 0xeb, 0x36, 0xcb, 0xd6, - 0x17, 0xba, 0x26, 0xa7, 0xfe, 0xf4, 0x25, 0xdf, 0x4b, 0xfd, 0x43, 0xac, 0xe3, 0x70, 0xcd, 0xf1, - 0xe6, 0xff, 0x0e, 0x27, 0xee, 0xc9, 0xa7, 0xdd, 0x73, 0xa4, 0x3b, 0x91, 0xa5, 0xdc, 0xc6, 0xde, - 0x9a, 0x7d, 0x25, 0xe3, 0x59, 0x47, 0xad, 0x57, 0x8c, 0x97, 0x2b, 0x1f, 0x8a, 0x1e, 0x6e, 0x7e, - 0x51, 0xdb, 0xbb, 0xfb, 0x20, 0xd6, 0xe7, 0x45, 0x09, 0x57, 0xef, 0xfe, 0x3b, 0x00, 0x00, 0xff, - 0xff, 0x61, 0xa9, 0xef, 0xf8, 0xe7, 0x21, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x19, 0xcb, 0x8e, 0x1b, 0xc7, + 0xd1, 0x7c, 0x2c, 0x1f, 0x45, 0xee, 0x2e, 0xd5, 0x5a, 0x4b, 0xd4, 0x4a, 0x86, 0xa4, 0xb1, 0x0d, + 0x2b, 0x81, 0xb3, 0x4a, 0xe4, 0x3c, 0x1c, 0xc9, 0x86, 0x43, 0x91, 0xb4, 0xb5, 0x5a, 0x89, 0xbb, + 0xe9, 0x5d, 0xca, 0x71, 0x10, 0x60, 0xd0, 0x9a, 0x69, 0x2d, 0xdb, 0x3b, 0x9c, 0x61, 0xa6, 0x9b, + 0x2b, 0xd3, 0x87, 0x00, 0xc9, 0x17, 0x04, 0xb9, 0xc4, 0x47, 0xdf, 0x02, 0xe4, 0x18, 0x20, 0x87, + 0xdc, 0x72, 0xcc, 0x3d, 0x47, 0xe7, 0x0b, 0x82, 0x7c, 0x40, 0x8e, 0x41, 0x57, 0xf7, 0x0c, 0x67, + 0xf8, 0x50, 0x24, 0xe4, 0x94, 0x13, 0xbb, 0xaa, 0xab, 0x6a, 0xaa, 0xeb, 0xd1, 0x55, 0xd5, 0x84, + 0xcd, 0x09, 0x13, 0xb1, 0x08, 0x4f, 0xf7, 0x26, 0x71, 0xa4, 0x22, 0x52, 0xc3, 0x9f, 0xa7, 0xd3, + 0x67, 0xbb, 0x17, 0xe5, 0x2c, 0xf4, 0x5c, 0xc9, 0x95, 0x12, 0xe1, 0xa9, 0x34, 0xdb, 0xbb, 0x0e, + 0x9b, 0x4c, 0x02, 0xe1, 0x31, 0x25, 0xa2, 0xd0, 0x1d, 0x73, 0xc5, 0x7c, 0xa6, 0x98, 0x3b, 0xe6, + 0x52, 0xb2, 0x53, 0x6e, 0x68, 0x1c, 0x06, 0x57, 0x3f, 0xe6, 0xca, 0x1b, 0x89, 0xf0, 0xf4, 0x3e, + 0xf3, 0xce, 0xb8, 0x3f, 0x9c, 0xf4, 0x98, 0x62, 0x3d, 0xae, 0x98, 0x08, 0x24, 0xb9, 0x0e, 0x0d, + 0x64, 0x0a, 0xa7, 0xe3, 0xa7, 0x3c, 0x6e, 0x17, 0x6e, 0x14, 0x6e, 0x6d, 0x52, 0xd0, 0xa8, 0x01, + 0x62, 0xc8, 0x4d, 0x68, 0xaa, 0x48, 0xb1, 0x20, 0xa1, 0x28, 0x22, 0x45, 0x03, 0x71, 0x86, 0xc4, + 0xf9, 0x6d, 0x15, 0x2a, 0x5a, 0xf6, 0x74, 0x42, 0x76, 0x60, 0xc3, 0x0b, 0x22, 0xef, 0x0c, 0x05, + 0x95, 0xa9, 0x01, 0xc8, 0x16, 0x14, 0x85, 0x8f, 0x9c, 0x75, 0x5a, 0x14, 0x3e, 0xf9, 0x08, 0x6a, + 0x5e, 0x14, 0x2a, 0xe6, 0x29, 0xd9, 0x2e, 0xdd, 0x28, 0xdd, 0x6a, 0xdc, 0x79, 0x73, 0x2f, 0x39, + 0xe9, 0xde, 0xf1, 0x2c, 0xf4, 0xf6, 0x43, 0xa9, 0x58, 0x10, 0xe0, 0xc1, 0xba, 0x86, 0xf2, 0xc9, + 0x1d, 0x9a, 0x32, 0x91, 0x1f, 0x43, 0xc3, 0x8b, 0xc6, 0xe3, 0x69, 0x28, 0x94, 0xe0, 0xb2, 0x5d, + 0x46, 0x19, 0x97, 0xf3, 0x32, 0xba, 0x96, 0x60, 0x46, 0xb3, 0xb4, 0xe4, 0x10, 0xb6, 0x13, 0x31, + 0xd6, 0x06, 0xed, 0x8d, 0x1b, 0x85, 0x5b, 0x8d, 0x3b, 0x6f, 0xcf, 0xd9, 0x5f, 0x60, 0x30, 0xba, + 0xc8, 0x4d, 0x86, 0x40, 0x32, 0xf2, 0x13, 0x99, 0x95, 0x57, 0x91, 0xb9, 0x42, 0x00, 0x79, 0x0f, + 0xaa, 0x93, 0x38, 0x7a, 0x26, 0x02, 0xde, 0xae, 0xa2, 0xac, 0x2b, 0x73, 0x59, 0x89, 0x8c, 0x23, + 0x43, 0x40, 0x13, 0x4a, 0xf2, 0x18, 0xb6, 0xec, 0x32, 0xd1, 0xa3, 0xf6, 0x2a, 0x7a, 0x2c, 0x30, + 0x93, 0xdb, 0x50, 0xb5, 0x11, 0xd7, 0xae, 0xa3, 0x9c, 0xd7, 0xf3, 0x26, 0x3e, 0x36, 0x9b, 0x34, + 0xa1, 0xd2, 0xc6, 0x4d, 0x42, 0x34, 0x51, 0x00, 0x5e, 0xc9, 0xb8, 0x0b, 0xdc, 0xe4, 0x1e, 0x34, + 0x9e, 0x4d, 0x83, 0xe0, 0x80, 0xcf, 0x74, 0x62, 0xb4, 0x1b, 0x8b, 0x96, 0xd0, 0x5a, 0xd8, 0xcd, + 0x8f, 0xa7, 0x41, 0x40, 0xb3, 0xd4, 0xda, 0x33, 0x19, 0x30, 0x51, 0xa8, 0xf9, 0x4a, 0x9e, 0x59, + 0x16, 0x40, 0x3a, 0xd0, 0x7a, 0xce, 0x94, 0x37, 0x3a, 0x0c, 0x83, 0x59, 0xc7, 0xf3, 0xa2, 0x69, + 0xa8, 0xda, 0x9b, 0xab, 0xcc, 0x63, 0x37, 0xe9, 0x12, 0x39, 0x71, 0xe1, 0xf2, 0x22, 0x2e, 0x51, + 0x6f, 0xeb, 0x55, 0xd4, 0x5b, 0x27, 0xc5, 0xf9, 0x57, 0x19, 0x9a, 0x8f, 0xa7, 0x81, 0x12, 0xc9, + 0x17, 0x09, 0x94, 0x43, 0x36, 0xe6, 0x98, 0x97, 0x75, 0x8a, 0x6b, 0x72, 0x0d, 0xea, 0x4a, 0x8c, + 0xb9, 0x54, 0x6c, 0x3c, 0xc1, 0xec, 0x2c, 0xd1, 0x39, 0x42, 0xef, 0x0a, 0x9f, 0x87, 0x4a, 0x78, + 0x51, 0xd8, 0x2e, 0x21, 0xdb, 0x1c, 0x41, 0x3e, 0x02, 0xf0, 0xa2, 0x20, 0x8a, 0xdd, 0x11, 0x93, + 0x23, 0x9b, 0x80, 0x37, 0xe6, 0x4a, 0x67, 0xbf, 0xbd, 0xd7, 0xd5, 0x84, 0x0f, 0x98, 0x1c, 0xd1, + 0xba, 0x97, 0x2c, 0xc9, 0x15, 0x7d, 0x07, 0x68, 0x01, 0xc2, 0xc7, 0x04, 0x2c, 0xd1, 0x2a, 0xc2, + 0xfb, 0x3e, 0x79, 0x07, 0xb6, 0xcf, 0xf8, 0xcc, 0x63, 0xb1, 0xef, 0xda, 0xeb, 0x10, 0xd3, 0xa9, + 0x4e, 0xb7, 0x2c, 0xfa, 0xc8, 0x60, 0xc9, 0x65, 0xa8, 0x9e, 0xf1, 0x99, 0x3b, 0x15, 0x3e, 0xe6, + 0x48, 0x9d, 0x56, 0xce, 0xf8, 0x6c, 0x28, 0x7c, 0xf2, 0x01, 0x54, 0xc4, 0x98, 0x9d, 0x72, 0x1d, + 0xff, 0x5a, 0xb3, 0xb7, 0xd6, 0x68, 0xb6, 0x8f, 0xe7, 0x51, 0xb3, 0x7d, 0x4d, 0x4c, 0x2d, 0x0f, + 0xb9, 0x0d, 0x17, 0xbd, 0xa9, 0x54, 0xd1, 0x58, 0x7c, 0x69, 0xae, 0x56, 0x54, 0x0c, 0x53, 0xa0, + 0x4e, 0x49, 0x6e, 0x0b, 0x8f, 0xb6, 0x7b, 0x13, 0xea, 0xe9, 0x19, 0xf5, 0x15, 0x28, 0x42, 0x9f, + 0x7f, 0xd1, 0x2e, 0xdc, 0x28, 0xdd, 0x2a, 0x51, 0x03, 0xec, 0x7e, 0x53, 0x80, 0xcd, 0xdc, 0xd7, + 0xb2, 0xca, 0x17, 0x72, 0xca, 0x27, 0xae, 0x2a, 0x66, 0x5c, 0xd5, 0x86, 0xea, 0x84, 0xcd, 0x82, + 0x88, 0xf9, 0xe8, 0x8a, 0x26, 0x4d, 0x40, 0xfd, 0xb9, 0xe7, 0xc2, 0x57, 0xda, 0x07, 0xda, 0x88, + 0x06, 0x20, 0x97, 0xa0, 0x32, 0xe2, 0xe2, 0x74, 0xa4, 0xac, 0x6d, 0x2d, 0x44, 0x76, 0xa1, 0xa6, + 0x13, 0x5c, 0x8a, 0x2f, 0x39, 0xda, 0xb4, 0x44, 0x53, 0x98, 0xbc, 0x09, 0x9b, 0x31, 0xae, 0x5c, + 0xc5, 0xe2, 0x53, 0xae, 0xd0, 0xa6, 0x25, 0xda, 0x34, 0xc8, 0x13, 0xc4, 0xcd, 0x2f, 0xf8, 0x5a, + 0xe6, 0x82, 0x77, 0xfe, 0x5e, 0x80, 0x8b, 0x8f, 0x22, 0x8f, 0x05, 0xd6, 0x33, 0x47, 0x56, 0xb9, + 0x1f, 0x40, 0xf9, 0x8c, 0xcf, 0x24, 0x9a, 0xa2, 0x71, 0xe7, 0xe6, 0xdc, 0x0b, 0x2b, 0x88, 0xf7, + 0x0e, 0xf8, 0x8c, 0x22, 0x39, 0xb9, 0x0b, 0xcd, 0xb1, 0x76, 0x13, 0xb3, 0xd9, 0x55, 0xc4, 0x9c, + 0xb8, 0xb4, 0xda, 0x89, 0x34, 0x47, 0xab, 0x4f, 0x38, 0x61, 0x52, 0x3e, 0x8f, 0x62, 0xdf, 0x46, + 0x6d, 0x0a, 0xef, 0x7e, 0x07, 0x4a, 0x07, 0x7c, 0xb6, 0x32, 0x17, 0x08, 0x94, 0x75, 0xd1, 0xc3, + 0x4f, 0x35, 0x29, 0xae, 0x9d, 0xbf, 0x14, 0xe0, 0xf5, 0x9c, 0xa2, 0x9c, 0xc7, 0x0f, 0x78, 0x10, + 0x44, 0x3a, 0x42, 0x6d, 0x64, 0xba, 0xe7, 0x3c, 0x96, 0x22, 0x0a, 0x51, 0xd8, 0x06, 0xdd, 0xb2, + 0xe8, 0x27, 0x06, 0xab, 0x9d, 0x3c, 0xe1, 0x1c, 0x83, 0xdc, 0x48, 0xae, 0x68, 0x70, 0xdf, 0xc7, + 0xba, 0xcb, 0xcf, 0x85, 0xc7, 0x5d, 0x54, 0xc5, 0x68, 0x0a, 0x06, 0x35, 0xd0, 0x0a, 0xcd, 0x09, + 0xd4, 0x6c, 0xc2, 0xd1, 0xbb, 0x29, 0xc1, 0xc9, 0x6c, 0x82, 0xd9, 0x2b, 0xc5, 0x69, 0xc8, 0xd4, + 0x34, 0xe6, 0xe8, 0xe5, 0x26, 0x9d, 0x23, 0x9c, 0xaf, 0x0b, 0xd0, 0xd2, 0x6a, 0x67, 0x2b, 0xe9, + 0x9a, 0xea, 0xfc, 0x0e, 0x6c, 0x8b, 0x0c, 0x95, 0x9b, 0x96, 0xea, 0xad, 0x2c, 0x3a, 0xa7, 0x33, + 0xaa, 0x54, 0x5a, 0x52, 0x29, 0x31, 0x6c, 0x39, 0x1f, 0xb9, 0x89, 0x89, 0x36, 0xb0, 0x75, 0x48, + 0x40, 0xe7, 0x9f, 0x05, 0xb8, 0xbc, 0xa6, 0xd8, 0xbf, 0x64, 0x1f, 0xf1, 0x26, 0x6c, 0xda, 0x8a, + 0xe5, 0x62, 0xea, 0x5a, 0x95, 0x9a, 0x16, 0x69, 0xf2, 0xec, 0x0a, 0xd4, 0x78, 0x28, 0xdd, 0x8c, + 0x62, 0x55, 0x1e, 0x4a, 0xb4, 0xf1, 0x4d, 0x68, 0x06, 0x4c, 0x2a, 0x77, 0x3a, 0xf1, 0x99, 0xe2, + 0xe6, 0x1e, 0x2a, 0xd3, 0x86, 0xc6, 0x0d, 0x0d, 0x4a, 0x9f, 0x59, 0xce, 0xa4, 0xe2, 0x63, 0x57, + 0xb1, 0x53, 0x5d, 0xd6, 0x4b, 0xfa, 0xcc, 0x06, 0x75, 0xc2, 0x4e, 0x25, 0x79, 0x1b, 0xb6, 0x02, + 0x1d, 0x23, 0x6e, 0x28, 0xbc, 0x33, 0xfc, 0x88, 0xb9, 0x8a, 0x36, 0x11, 0x3b, 0xb0, 0x48, 0xe7, + 0xd7, 0x15, 0xb8, 0xb2, 0xb6, 0xb3, 0x21, 0xdf, 0x85, 0x9d, 0xac, 0x22, 0x2e, 0xf2, 0x06, 0x33, + 0x7b, 0x7a, 0x92, 0x51, 0xe8, 0x91, 0xd9, 0xf9, 0x3f, 0x36, 0x85, 0xf6, 0x2d, 0xf3, 0x7d, 0xee, + 0xe3, 0x85, 0x5a, 0xa3, 0x06, 0xd0, 0x71, 0xf2, 0x54, 0x3b, 0x99, 0xfb, 0xd8, 0x32, 0xd4, 0x68, + 0x02, 0x6a, 0xfa, 0xf1, 0x54, 0xeb, 0xd4, 0x30, 0xf4, 0x08, 0x68, 0xfa, 0x98, 0x8f, 0xa3, 0x73, + 0xee, 0x63, 0x45, 0xaf, 0xd1, 0x04, 0x24, 0x37, 0xa0, 0x39, 0x62, 0xd2, 0x45, 0xb1, 0xee, 0x54, + 0x62, 0x6d, 0xae, 0x51, 0x18, 0x31, 0xd9, 0xd1, 0xa8, 0x21, 0x5e, 0xf0, 0xe7, 0x3c, 0x16, 0xcf, + 0x92, 0xd6, 0x59, 0x2a, 0xa6, 0xa6, 0xa6, 0xf4, 0x96, 0x28, 0xc9, 0x6e, 0x1d, 0xe3, 0x0e, 0x36, + 0xc1, 0xf1, 0x54, 0xaa, 0x84, 0x72, 0x1b, 0x29, 0x1b, 0x88, 0xb3, 0x24, 0x1f, 0xc2, 0x55, 0xdb, + 0x19, 0xba, 0x31, 0xff, 0xe5, 0x94, 0x4b, 0x65, 0xbc, 0x88, 0x2c, 0xbc, 0xdd, 0x42, 0x8e, 0xb6, + 0x25, 0xa1, 0x86, 0x02, 0x9d, 0xa9, 0xf9, 0xf9, 0x7a, 0x76, 0x93, 0x06, 0x17, 0xd6, 0xb2, 0x77, + 0x31, 0x33, 0x3e, 0x82, 0x6b, 0x8b, 0xec, 0xda, 0x1c, 0x8a, 0xdb, 0xcf, 0x13, 0xe4, 0xbf, 0x92, + 0xe7, 0xa7, 0x48, 0x61, 0xbe, 0xbf, 0x5e, 0x80, 0x51, 0xe0, 0xe2, 0x7a, 0x01, 0x46, 0x83, 0x9b, + 0xd0, 0xf4, 0x85, 0x9c, 0x04, 0x6c, 0x66, 0xe2, 0x6b, 0x07, 0x5d, 0xdf, 0xb0, 0x38, 0x1d, 0x63, + 0xce, 0xf3, 0xe5, 0x7c, 0x4f, 0xda, 0x93, 0xd5, 0xf9, 0xbe, 0x14, 0xd4, 0xc5, 0x15, 0x41, 0xbd, + 0x18, 0xb9, 0xa5, 0xa5, 0xc8, 0x75, 0xee, 0xc3, 0xee, 0xe2, 0x87, 0x8f, 0xa6, 0x4f, 0x03, 0xe1, + 0x75, 0x47, 0xec, 0x25, 0xef, 0x1a, 0xe7, 0xcf, 0x25, 0xd8, 0xcc, 0x8d, 0x15, 0xff, 0x95, 0xaf, + 0x89, 0x89, 0x79, 0x1d, 0x1a, 0x93, 0x58, 0x9c, 0x33, 0xc5, 0xdd, 0x33, 0x3e, 0xb3, 0xd5, 0x1b, + 0x2c, 0x4a, 0x57, 0xa3, 0x1b, 0xfa, 0x56, 0x95, 0x5e, 0x2c, 0x26, 0x5a, 0x2f, 0xcc, 0xcb, 0x26, + 0xcd, 0xa2, 0x74, 0x31, 0xff, 0x3c, 0x12, 0xa1, 0xcd, 0xca, 0x1a, 0xb5, 0x90, 0x2e, 0x75, 0x26, + 0x56, 0xb9, 0x8f, 0xc5, 0xbc, 0x46, 0x53, 0x78, 0x9e, 0x34, 0xd5, 0x6c, 0xd2, 0x1c, 0x42, 0xcb, + 0x7a, 0x57, 0xba, 0x2a, 0x72, 0xb5, 0x1c, 0xdb, 0x21, 0xbd, 0xbd, 0x6e, 0x78, 0xb2, 0xe4, 0x27, + 0xd1, 0xc3, 0x48, 0x84, 0x74, 0x2b, 0xce, 0xc1, 0xe4, 0x1e, 0xd4, 0x92, 0x96, 0xdd, 0x8e, 0x08, + 0xd7, 0xd7, 0x08, 0xb2, 0xb3, 0x82, 0xa4, 0x29, 0x83, 0xae, 0x60, 0x3c, 0xf4, 0xe2, 0xd9, 0x44, + 0xa5, 0x49, 0x3f, 0x47, 0x60, 0x7d, 0x9b, 0x70, 0x4f, 0xb1, 0x79, 0xea, 0xcf, 0x11, 0xba, 0x68, + 0x59, 0x52, 0x9d, 0xc0, 0xd8, 0x64, 0x34, 0xd1, 0x72, 0x5b, 0x73, 0xf4, 0x01, 0x9f, 0x49, 0xe7, + 0x37, 0x25, 0xb8, 0xfa, 0x82, 0x13, 0x59, 0x7f, 0x15, 0x52, 0x7f, 0xbd, 0x01, 0x30, 0xc1, 0xd8, + 0x40, 0x77, 0x19, 0xff, 0xd7, 0x0d, 0x46, 0x7b, 0x2b, 0x75, 0x7a, 0x29, 0xeb, 0xf4, 0x17, 0x5c, + 0xac, 0x97, 0xa1, 0xea, 0x8d, 0x98, 0x4a, 0xda, 0xdc, 0x3a, 0xad, 0x68, 0x70, 0xdf, 0xd7, 0x71, + 0x9b, 0x8c, 0x7d, 0x33, 0xbd, 0x5b, 0x31, 0x8e, 0x4f, 0x71, 0xfb, 0xe8, 0x44, 0x93, 0xbe, 0x55, + 0xf3, 0x31, 0x04, 0xc8, 0x19, 0x90, 0x98, 0x9f, 0x73, 0x16, 0x70, 0x5f, 0x5f, 0x72, 0x31, 0x97, + 0x32, 0x6d, 0x74, 0x3f, 0x78, 0x29, 0x37, 0xee, 0x51, 0xcb, 0xdf, 0x49, 0xd8, 0xfb, 0xa1, 0x8a, + 0x67, 0xf4, 0x42, 0xbc, 0x88, 0xdf, 0xed, 0xc1, 0xa5, 0xd5, 0xc4, 0xa4, 0x05, 0x25, 0x6d, 0x21, + 0xd3, 0x44, 0xe9, 0xa5, 0x56, 0xf7, 0x9c, 0x05, 0x53, 0x6e, 0xa3, 0xdf, 0x00, 0x77, 0x8b, 0xef, + 0x17, 0x9c, 0xdf, 0x15, 0xa1, 0xb5, 0x98, 0x81, 0xe4, 0xc3, 0xcc, 0x2b, 0xc0, 0x52, 0x83, 0xb8, + 0xa6, 0x56, 0x66, 0xde, 0x00, 0x3e, 0x81, 0xa6, 0x75, 0x94, 0x36, 0xa8, 0x6c, 0x17, 0x17, 0x3b, + 0xfd, 0xf5, 0x29, 0x4f, 0x1b, 0x93, 0x74, 0xad, 0x67, 0xcc, 0x6a, 0xd2, 0x68, 0x96, 0x30, 0x84, + 0x5f, 0xa0, 0x46, 0xd2, 0x73, 0x26, 0x1c, 0xff, 0xc3, 0x4b, 0x84, 0xf3, 0x23, 0xd8, 0xc6, 0x5d, + 0xad, 0x90, 0x2d, 0x5d, 0x2f, 0x77, 0x15, 0x7d, 0x00, 0x3b, 0x09, 0xe3, 0x63, 0xf3, 0xd6, 0x23, + 0x29, 0x67, 0x2f, 0xcb, 0xfd, 0x13, 0xb8, 0x64, 0x86, 0x53, 0x25, 0xce, 0x85, 0x9a, 0x75, 0x79, + 0xa8, 0x78, 0xfc, 0x02, 0xfe, 0x16, 0x94, 0x84, 0x6f, 0xcc, 0xdb, 0xa4, 0x7a, 0xe9, 0xf4, 0xcc, + 0x75, 0x9a, 0x97, 0xd0, 0xf1, 0x3c, 0x8e, 0x79, 0xfb, 0xb2, 0x52, 0xfa, 0x26, 0x2f, 0xf3, 0x52, + 0x7a, 0x42, 0x8e, 0x85, 0x94, 0xaf, 0x20, 0xe6, 0xeb, 0x02, 0x34, 0xb5, 0x9c, 0xfb, 0x51, 0x74, + 0x36, 0x66, 0xf1, 0xd9, 0x7a, 0xc6, 0x69, 0x1c, 0x58, 0x33, 0xe8, 0x65, 0xda, 0xac, 0x96, 0x32, + 0xcd, 0xea, 0x55, 0xa8, 0x63, 0xa1, 0x71, 0x35, 0xad, 0x49, 0xe4, 0x1a, 0x22, 0x86, 0x71, 0x90, + 0xed, 0x38, 0x36, 0xf2, 0x1d, 0xc7, 0x1b, 0x00, 0x3e, 0x0f, 0xb8, 0xee, 0xdc, 0x98, 0xc2, 0x44, + 0x2e, 0xd3, 0xba, 0xc5, 0x74, 0x94, 0xf3, 0x2b, 0x78, 0x5d, 0x6b, 0xd8, 0x0f, 0xe5, 0x50, 0xf2, + 0x58, 0x7f, 0xc8, 0x8c, 0xe9, 0x6b, 0x54, 0xdd, 0x85, 0xda, 0xd4, 0xd2, 0x59, 0x7d, 0x53, 0x18, + 0xa7, 0xe6, 0x11, 0x13, 0xd8, 0xa4, 0x9b, 0x1b, 0xa8, 0x8a, 0xf0, 0x7e, 0xae, 0x21, 0x2a, 0xe7, + 0xd4, 0x73, 0x1e, 0x9a, 0xe4, 0xeb, 0x06, 0x9c, 0xc5, 0x0f, 0x84, 0x54, 0x51, 0x3c, 0xcb, 0x5e, + 0x4b, 0x85, 0xdc, 0xb5, 0xf4, 0x06, 0x80, 0xa7, 0x09, 0xcd, 0x59, 0x8a, 0xe6, 0x2c, 0x16, 0xd3, + 0x51, 0xce, 0xdf, 0x0a, 0x40, 0xb4, 0x30, 0xfb, 0xf4, 0x74, 0x24, 0x3c, 0x3d, 0x6e, 0xac, 0x1c, + 0xa9, 0x32, 0x33, 0x6b, 0x71, 0xcd, 0xcc, 0x5a, 0xc2, 0x89, 0x60, 0x69, 0x66, 0x2d, 0x23, 0x3a, + 0x99, 0x59, 0xaf, 0x42, 0x1d, 0x5b, 0x00, 0x1c, 0x5a, 0xcd, 0x0c, 0x81, 0x43, 0xeb, 0xf1, 0xca, + 0xa1, 0xb5, 0x82, 0x04, 0x6b, 0x86, 0xd6, 0x6a, 0x76, 0x68, 0x1d, 0xc1, 0xc5, 0xe5, 0x93, 0xc8, + 0xf5, 0x73, 0xf9, 0xfb, 0x50, 0x9b, 0x58, 0x22, 0x7b, 0xd9, 0x5c, 0xcb, 0xe7, 0x79, 0x5e, 0x12, + 0x4d, 0xa9, 0x9d, 0x3f, 0x14, 0xa1, 0x91, 0x79, 0x10, 0x5a, 0xe3, 0xf7, 0x36, 0x54, 0xed, 0x75, + 0x9e, 0xd8, 0xcb, 0x82, 0x59, 0x95, 0x4a, 0x39, 0x95, 0xf2, 0xc5, 0xca, 0xb4, 0x0e, 0x99, 0x62, + 0x45, 0xa0, 0x3c, 0x61, 0x6a, 0x64, 0x0b, 0x0f, 0xae, 0x53, 0x4f, 0x55, 0x32, 0x9e, 0xd2, 0xfa, + 0xe0, 0x13, 0x87, 0xe9, 0xd7, 0x0d, 0xa0, 0xb1, 0x7c, 0x1c, 0x7d, 0x2e, 0x70, 0xd4, 0xaf, 0x53, + 0x03, 0x68, 0x2f, 0x3d, 0x67, 0x41, 0xc0, 0x95, 0x6d, 0xdf, 0x2d, 0xa4, 0xe5, 0xea, 0x08, 0xb2, + 0x75, 0x1c, 0xd7, 0xe8, 0x51, 0xe1, 0xfb, 0x3c, 0xb4, 0xf5, 0xdb, 0x42, 0xeb, 0x7b, 0x77, 0xe7, + 0x2b, 0x6b, 0xa9, 0xe4, 0x09, 0x6f, 0xb5, 0xa5, 0x32, 0xf6, 0x28, 0xae, 0x7c, 0x3a, 0x29, 0xe5, + 0x27, 0xfb, 0xcc, 0x04, 0x8d, 0x6b, 0x6c, 0x56, 0x79, 0x2c, 0xce, 0xb9, 0xef, 0x3e, 0x8b, 0xa3, + 0xb1, 0x35, 0x50, 0xc3, 0xe2, 0x3e, 0x8e, 0xa3, 0x31, 0xb9, 0x07, 0xbb, 0xa6, 0xad, 0x94, 0xdc, + 0x77, 0x71, 0xc3, 0x4e, 0xc7, 0xf8, 0xb6, 0x63, 0x72, 0xfc, 0x32, 0x36, 0x99, 0x92, 0xfb, 0xbd, + 0x74, 0x7f, 0x5f, 0x6f, 0x9b, 0x51, 0x29, 0xf4, 0x12, 0xf1, 0xc6, 0xac, 0x60, 0x50, 0x28, 0xfd, + 0x7b, 0x50, 0xb3, 0x15, 0x24, 0xa9, 0xdc, 0x6b, 0xde, 0x0e, 0x53, 0x32, 0x67, 0x6a, 0xca, 0x45, + 0xe6, 0xb5, 0x93, 0xdc, 0x46, 0x3b, 0xe0, 0xcb, 0x68, 0x61, 0xd5, 0x03, 0xa4, 0xa5, 0xa5, 0x09, + 0x95, 0xfe, 0xac, 0x7d, 0x42, 0x4b, 0x42, 0x78, 0x99, 0x43, 0xef, 0xd2, 0x94, 0xcc, 0xf9, 0x77, + 0xc1, 0xdc, 0x1e, 0xc7, 0xec, 0x3c, 0x6d, 0x01, 0xb2, 0xa1, 0x5a, 0xc8, 0x87, 0xea, 0xaa, 0xc7, + 0xab, 0x6b, 0x50, 0x7f, 0xc6, 0xce, 0xa3, 0x69, 0x2c, 0x94, 0x71, 0x4d, 0x8d, 0xce, 0x11, 0x2f, + 0xb8, 0x56, 0x6f, 0x42, 0xd3, 0x34, 0xf5, 0x6e, 0x36, 0x7b, 0x1b, 0x06, 0x67, 0xa6, 0x8e, 0x6f, + 0xc3, 0x05, 0x73, 0x1f, 0xca, 0x51, 0x14, 0x2b, 0x6c, 0xc0, 0xa4, 0x8d, 0xd7, 0x6d, 0xdc, 0x38, + 0xd6, 0x78, 0xdd, 0x88, 0x49, 0x5d, 0x02, 0x78, 0x28, 0xed, 0x33, 0x9e, 0x5e, 0xea, 0x38, 0x12, + 0xd2, 0x55, 0x5c, 0x26, 0x61, 0x5b, 0x11, 0xf2, 0x84, 0x4b, 0xf5, 0xb0, 0x5c, 0x2b, 0xb7, 0x36, + 0x9c, 0xdf, 0x17, 0xcc, 0xc5, 0xbd, 0xd4, 0xc3, 0xae, 0x09, 0xcb, 0xc5, 0x8e, 0xce, 0xd8, 0x20, + 0xd7, 0xd1, 0xf5, 0xe1, 0xfa, 0xc8, 0xdc, 0xc0, 0x2e, 0x8b, 0xbd, 0x91, 0x38, 0xe7, 0xae, 0x9c, + 0x4e, 0x26, 0x5a, 0x77, 0x1e, 0xb2, 0xa7, 0x81, 0x9d, 0x5f, 0x6a, 0xf4, 0x9a, 0x25, 0xeb, 0x18, + 0xaa, 0x63, 0x43, 0xd4, 0x37, 0x34, 0xce, 0x9f, 0x0a, 0x26, 0x18, 0x4e, 0xf4, 0x00, 0xaa, 0x47, + 0x5a, 0x1e, 0xbf, 0xe4, 0x93, 0xc9, 0x87, 0x50, 0xb1, 0x33, 0xac, 0xfe, 0xce, 0xd6, 0x62, 0xdf, + 0x9f, 0x11, 0xb8, 0x77, 0x32, 0x9f, 0x6e, 0xa9, 0x65, 0x72, 0xee, 0x42, 0x23, 0x83, 0x26, 0x0d, + 0xa8, 0x0e, 0x07, 0x07, 0x83, 0xc3, 0x4f, 0x07, 0xad, 0xd7, 0x34, 0x70, 0x42, 0x87, 0xc7, 0x27, + 0xfd, 0x5e, 0xab, 0x40, 0x2e, 0xc0, 0xe6, 0x70, 0x80, 0xe0, 0xa7, 0x87, 0xf4, 0xe4, 0xc1, 0x67, + 0xad, 0xa2, 0xf3, 0x75, 0xc9, 0xcc, 0x7f, 0x4f, 0x32, 0xf3, 0xb5, 0xed, 0x4b, 0xd7, 0x28, 0x4f, + 0xa0, 0x8c, 0xf9, 0x63, 0x83, 0x49, 0xaf, 0xf5, 0x81, 0x54, 0x64, 0x13, 0xbc, 0xa8, 0x22, 0x1d, + 0x5c, 0xde, 0x48, 0x5f, 0x41, 0xe1, 0x69, 0x92, 0xe3, 0x73, 0x84, 0x76, 0x89, 0x9d, 0x58, 0x4c, + 0x3d, 0xb3, 0xcf, 0x1a, 0x29, 0xae, 0x83, 0x0f, 0x86, 0x31, 0x97, 0x93, 0x28, 0x94, 0xc9, 0xa5, + 0x98, 0xc2, 0xfa, 0x7e, 0x8d, 0xf9, 0x24, 0x10, 0x86, 0xd9, 0xc4, 0x5f, 0xdd, 0x62, 0x3a, 0x8a, + 0xf0, 0xd5, 0xef, 0x08, 0x35, 0xb4, 0xec, 0xf7, 0xf3, 0x96, 0x5d, 0x71, 0xea, 0xbd, 0x27, 0x4b, + 0x2f, 0x0d, 0x2b, 0x5f, 0x1f, 0x8c, 0x0f, 0xeb, 0x69, 0x07, 0xf7, 0x33, 0x20, 0xcb, 0x9c, 0x4b, + 0xbe, 0x38, 0xea, 0x0f, 0x7a, 0xfb, 0x83, 0x4f, 0x5a, 0x05, 0xd2, 0x84, 0x5a, 0xa7, 0xdb, 0xed, + 0x1f, 0x69, 0xcf, 0x14, 0x35, 0xd4, 0xeb, 0x77, 0x1f, 0xed, 0x0f, 0xfa, 0xbd, 0x56, 0x49, 0x43, + 0xdd, 0xce, 0xa0, 0xdb, 0x7f, 0xd4, 0xef, 0xb5, 0xca, 0xce, 0x3f, 0x0a, 0xa6, 0xb5, 0xeb, 0xe6, + 0xc6, 0xfc, 0x1e, 0xf7, 0x84, 0x5c, 0xff, 0x7e, 0x78, 0x0d, 0xea, 0xd6, 0x9e, 0xfb, 0x49, 0xa4, + 0xcd, 0x11, 0xe4, 0x17, 0xb0, 0xed, 0x5b, 0x7e, 0x37, 0x17, 0x79, 0xef, 0x2d, 0x36, 0xc9, 0xab, + 0x3e, 0xb9, 0x97, 0x2c, 0xac, 0x79, 0xb6, 0xfc, 0x1c, 0xec, 0xbc, 0x0b, 0x5b, 0x79, 0x8a, 0xdc, + 0x61, 0x5f, 0xcb, 0x1d, 0xb6, 0xe0, 0x7c, 0x53, 0x84, 0xed, 0x85, 0xff, 0xce, 0xd6, 0x97, 0xfb, + 0xc5, 0x07, 0x8d, 0xe2, 0xd2, 0x83, 0x06, 0x79, 0x17, 0x48, 0x96, 0xc4, 0xcd, 0x4e, 0x86, 0xad, + 0x0c, 0xa1, 0xb9, 0xab, 0xb2, 0xfd, 0x43, 0xf9, 0x55, 0xfa, 0x07, 0xf2, 0x53, 0xd8, 0x91, 0x91, + 0x27, 0x58, 0xe0, 0x06, 0x22, 0x3c, 0x4b, 0xff, 0x05, 0x6e, 0x6f, 0xa0, 0x94, 0x85, 0x89, 0xfb, + 0x18, 0x29, 0x1f, 0x89, 0xf0, 0x2c, 0xf9, 0x7b, 0x8e, 0xc8, 0x45, 0x14, 0x8a, 0xd4, 0x13, 0x6b, + 0xd2, 0x58, 0xba, 0x7e, 0xfa, 0xbf, 0xe5, 0x0a, 0x91, 0x4b, 0x9d, 0x2b, 0x25, 0x7c, 0x11, 0x25, + 0x1d, 0x09, 0x40, 0xd9, 0x73, 0x3b, 0x91, 0x64, 0xbb, 0xbf, 0x42, 0xbe, 0xfb, 0x3b, 0x80, 0x86, + 0xfd, 0x8b, 0xfa, 0x44, 0xd7, 0xe5, 0x22, 0x46, 0xc3, 0xb7, 0xe6, 0x5f, 0xec, 0xcc, 0xff, 0xd4, + 0x7e, 0x6c, 0xff, 0xd3, 0xb6, 0x42, 0xf7, 0x34, 0x03, 0xcd, 0x72, 0x3b, 0x7f, 0x2c, 0xc0, 0x96, + 0x56, 0x31, 0xf3, 0xe5, 0x1f, 0x42, 0x23, 0x4e, 0xa1, 0x64, 0xb4, 0xdc, 0x99, 0xcb, 0x9f, 0x93, + 0xd2, 0x2c, 0x21, 0xb9, 0x03, 0x3b, 0x72, 0xfa, 0xd4, 0x16, 0x5e, 0xf9, 0x50, 0x46, 0xe1, 0xfd, + 0x99, 0xe2, 0x49, 0x33, 0xb6, 0x72, 0x8f, 0xbc, 0x0b, 0x17, 0x12, 0x6f, 0xcc, 0x19, 0xcc, 0x1b, + 0xcf, 0xf2, 0x86, 0xf3, 0x55, 0x21, 0xed, 0x6e, 0x74, 0x71, 0xc5, 0xa1, 0x24, 0x8d, 0x3b, 0xbd, + 0x5c, 0x59, 0x3e, 0x2f, 0x41, 0xc5, 0x3e, 0x8c, 0x9a, 0xd2, 0x60, 0xa1, 0x6c, 0xe4, 0x96, 0x73, + 0x91, 0x7b, 0x0d, 0xea, 0xf3, 0x77, 0x81, 0x0d, 0x1c, 0x95, 0xe6, 0x88, 0x79, 0x12, 0x57, 0xb2, + 0xcd, 0xf0, 0x5f, 0x8b, 0x70, 0x21, 0xa3, 0x9a, 0x9e, 0xca, 0xa2, 0x90, 0xdc, 0x85, 0x0a, 0xc3, + 0x15, 0xea, 0xb8, 0x75, 0xc7, 0x59, 0xd9, 0x2d, 0x18, 0xe2, 0x3d, 0xf3, 0x43, 0x2d, 0x07, 0x79, + 0x0b, 0x36, 0xa3, 0xc0, 0xb7, 0x24, 0xc3, 0xb4, 0x08, 0xe5, 0x91, 0xb6, 0x85, 0xd1, 0x90, 0x1d, + 0xbe, 0xd7, 0x34, 0x24, 0x09, 0x95, 0x2e, 0xca, 0x15, 0xab, 0xdd, 0x05, 0xd8, 0x3c, 0xe8, 0x7f, + 0xd6, 0xed, 0xd0, 0x9e, 0xdb, 0xe9, 0xf5, 0x30, 0xdf, 0x09, 0x6c, 0x75, 0xba, 0xdd, 0xc3, 0xe1, + 0xe0, 0xe4, 0xd8, 0xe2, 0x0a, 0xe4, 0x22, 0x6c, 0x27, 0x64, 0xbd, 0xfe, 0xa3, 0xbe, 0xb9, 0x05, + 0x77, 0xa0, 0x95, 0x12, 0xd2, 0xfe, 0xe3, 0xc3, 0x27, 0x78, 0x1b, 0x02, 0x54, 0x1e, 0x1d, 0x76, + 0x0f, 0xf4, 0x5d, 0xa8, 0xaf, 0x8e, 0xe1, 0xc0, 0x42, 0x1b, 0x64, 0x1b, 0x1a, 0xc3, 0xfd, 0x9e, + 0x3b, 0x3c, 0xea, 0x75, 0xb4, 0x80, 0x0a, 0x69, 0x41, 0x73, 0xd0, 0x79, 0xdc, 0x77, 0xbb, 0x0f, + 0x3a, 0x83, 0x4f, 0xfa, 0xbd, 0x56, 0xd5, 0x39, 0x36, 0xdd, 0xc2, 0x52, 0xfe, 0x61, 0x07, 0xca, + 0xbf, 0x50, 0xc9, 0x70, 0xa4, 0xd7, 0x2b, 0xe6, 0xd1, 0x95, 0x2f, 0x4b, 0xf7, 0x37, 0x7f, 0xde, + 0xd8, 0xbb, 0x7d, 0x2f, 0x31, 0xc9, 0xd3, 0x0a, 0xae, 0xde, 0xfb, 0x4f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xdd, 0x37, 0x90, 0xb0, 0x28, 0x22, 0x00, 0x00, } diff --git a/protocol/protobuf/pairing.proto b/protocol/protobuf/pairing.proto index b837a76de..8870fa2d0 100644 --- a/protocol/protobuf/pairing.proto +++ b/protocol/protobuf/pairing.proto @@ -26,10 +26,10 @@ message Backup { FetchingBackedUpDataDetails profileDetails = 8; SyncSetting setting = 9; FetchingBackedUpDataDetails settingsDetails = 10; - SyncAllKeycards keycards = 11; - FetchingBackedUpDataDetails keycardsDetails = 12; - SyncWalletAccount walletAccount = 13; - FetchingBackedUpDataDetails walletAccountsDetails = 14; + SyncKeypairFull fullKeypair = 11; + FetchingBackedUpDataDetails fullKeypairDetails = 12; + SyncAccount watchOnlyAccount = 13; + FetchingBackedUpDataDetails watchOnlyAccountDetails = 14; } message MultiAccount { @@ -224,28 +224,35 @@ message SyncProfilePictures { repeated SyncProfilePicture pictures = 2; } -message SyncWalletAccount { +message SyncAccount { uint64 clock = 1; - bytes address = 2; - bool wallet = 3; - bool chat = 4; - string type = 5; - string storage = 6; - string path = 7; - bytes publicKey = 8; - string name = 9; - string color = 10; - bool hidden = 11; + bytes address = 2; + string key_uid = 3; + bytes public_key = 4; + string path = 5; + string name = 6; + string color = 7; + string emoji = 8; + bool wallet = 9; + bool chat = 10; + bool hidden = 11; bool removed = 12; - string emoji = 13; - string derived_from = 14; - string key_uid = 15; - string keypair_name = 16; - uint64 last_used_derivation_index = 17; } -message SyncWalletAccounts { - repeated SyncWalletAccount accounts = 1; +message SyncKeypair { + uint64 clock = 1; + string key_uid = 2; + string name = 3; + string type = 4; + string derived_from = 5; + uint64 last_used_derivation_index = 6; + string synced_from = 7; + repeated SyncAccount accounts = 8; +} + +message SyncKeypairFull { + SyncKeypair keypair = 1; + repeated SyncKeycard keycards = 2; } message SyncSavedAddress { @@ -358,11 +365,6 @@ message SyncKeycardAction { } } -message SyncAllKeycards { - repeated SyncKeycard keycards = 1; - uint64 clock = 2; -} - message SyncSocialLinkSetting { string text = 1; string url = 2; diff --git a/protocol/v1/status_message.go b/protocol/v1/status_message.go index aa81015f7..d4df847b9 100644 --- a/protocol/v1/status_message.go +++ b/protocol/v1/status_message.go @@ -294,8 +294,8 @@ func (m *StatusMessage) HandleApplication() error { return m.unmarshalProtobufData(new(protobuf.SyncSetting)) case protobuf.ApplicationMetadataMessage_COMMUNITY_ARCHIVE_MAGNETLINK: return m.unmarshalProtobufData(new(protobuf.CommunityMessageArchiveMagnetlink)) - case protobuf.ApplicationMetadataMessage_SYNC_WALLET_ACCOUNT: - return m.unmarshalProtobufData(new(protobuf.SyncWalletAccounts)) + case protobuf.ApplicationMetadataMessage_SYNC_ACCOUNT: + return m.unmarshalProtobufData(new(protobuf.SyncAccount)) case protobuf.ApplicationMetadataMessage_ACCEPT_CONTACT_REQUEST: return m.unmarshalProtobufData(new(protobuf.AcceptContactRequest)) case protobuf.ApplicationMetadataMessage_RETRACT_CONTACT_REQUEST: @@ -318,14 +318,16 @@ func (m *StatusMessage) HandleApplication() error { return m.unmarshalProtobufData((new(protobuf.SyncContactRequestDecision))) case protobuf.ApplicationMetadataMessage_SYNC_SAVED_ADDRESS: return m.unmarshalProtobufData(new(protobuf.SyncSavedAddress)) - case protobuf.ApplicationMetadataMessage_SYNC_ALL_KEYCARDS: - return m.unmarshalProtobufData(new(protobuf.SyncAllKeycards)) case protobuf.ApplicationMetadataMessage_SYNC_KEYCARD_ACTION: return m.unmarshalProtobufData(new(protobuf.SyncKeycardAction)) case protobuf.ApplicationMetadataMessage_SYNC_SOCIAL_LINK_SETTING: return m.unmarshalProtobufData(new(protobuf.SyncSocialLinkSetting)) case protobuf.ApplicationMetadataMessage_SYNC_ENS_USERNAME_DETAIL: return m.unmarshalProtobufData(new(protobuf.SyncEnsUsernameDetail)) + case protobuf.ApplicationMetadataMessage_SYNC_KEYPAIR: + return m.unmarshalProtobufData(new(protobuf.SyncKeypair)) + case protobuf.ApplicationMetadataMessage_SYNC_FULL_KEYPAIR: + return m.unmarshalProtobufData(new(protobuf.SyncKeypairFull)) } return nil } diff --git a/protocol/wakusync/response.go b/protocol/wakusync/response.go index 45975e9fc..54737eab8 100644 --- a/protocol/wakusync/response.go +++ b/protocol/wakusync/response.go @@ -4,31 +4,36 @@ import ( "encoding/json" "github.com/status-im/status-go/multiaccounts/accounts" - "github.com/status-im/status-go/multiaccounts/keycards" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/protocol/protobuf" ) type WakuBackedUpDataResponse struct { + Clock uint64 FetchingDataProgress map[string]protobuf.FetchingBackedUpDataDetails // key represents the data/section backup details refer to Profile *BackedUpProfile Setting *settings.SyncSettingField - Keycards []*keycards.Keycard - WalletAccount *accounts.Account + Keycards []*accounts.Keycard + Keypair *accounts.Keypair + WatchOnlyAccount *accounts.Account } func (sfwr *WakuBackedUpDataResponse) MarshalJSON() ([]byte, error) { responseItem := struct { + Clock uint64 `json:"clock,omitempty"` FetchingDataProgress map[string]FetchingBackupedDataDetails `json:"fetchingBackedUpDataProgress,omitempty"` Profile *BackedUpProfile `json:"backedUpProfile,omitempty"` Setting *settings.SyncSettingField `json:"backedUpSettings,omitempty"` - Keycards []*keycards.Keycard `json:"backedUpKeycards,omitempty"` - WalletAccount *accounts.Account `json:"backedUpWalletAccount,omitempty"` + Keycards []*accounts.Keycard `json:"backedUpKeycards,omitempty"` + Keypair *accounts.Keypair `json:"backedUpKeypair,omitempty"` + WatchOnlyAccount *accounts.Account `json:"backedUpWatchOnlyAccount,omitempty"` }{ - Profile: sfwr.Profile, - Setting: sfwr.Setting, - Keycards: sfwr.Keycards, - WalletAccount: sfwr.WalletAccount, + Clock: sfwr.Clock, + Profile: sfwr.Profile, + Setting: sfwr.Setting, + Keycards: sfwr.Keycards, + Keypair: sfwr.Keypair, + WatchOnlyAccount: sfwr.WatchOnlyAccount, } responseItem.FetchingDataProgress = sfwr.FetchingBackedUpDataDetails() diff --git a/server/pairing/payload_management.go b/server/pairing/payload_management.go index a607953ff..0a1b2019e 100644 --- a/server/pairing/payload_management.go +++ b/server/pairing/payload_management.go @@ -104,9 +104,9 @@ func (ppm *AccountPayloadMarshaller) multiaccountFromProtobuf(pbMultiAccount *pr } type RawMessagesPayload struct { - rawMessages []*protobuf.RawMessage - subAccounts []*accounts.Account - setting *settings.Settings + rawMessages []*protobuf.RawMessage + profileKeypair *accounts.Keypair + setting *settings.Settings } func NewRawMessagesPayload() *RawMessagesPayload { @@ -130,8 +130,8 @@ func (rmm *RawMessagePayloadMarshaller) MarshalProtobuf() (data []byte, err erro syncRawMessage := new(protobuf.SyncRawMessage) syncRawMessage.RawMessages = rmm.payload.rawMessages - if len(rmm.payload.subAccounts) > 0 { - syncRawMessage.SubAccountsJsonBytes, err = json.Marshal(rmm.payload.subAccounts) + if rmm.payload.profileKeypair != nil && len(rmm.payload.profileKeypair.KeyUID) > 0 { + syncRawMessage.SubAccountsJsonBytes, err = json.Marshal(rmm.payload.profileKeypair) if err != nil { return nil, err } @@ -153,7 +153,7 @@ func (rmm *RawMessagePayloadMarshaller) UnmarshalProtobuf(data []byte) error { return err } if syncRawMessage.SubAccountsJsonBytes != nil { - err = json.Unmarshal(syncRawMessage.SubAccountsJsonBytes, &rmm.payload.subAccounts) + err = json.Unmarshal(syncRawMessage.SubAccountsJsonBytes, &rmm.payload.profileKeypair) if err != nil { return err } diff --git a/server/pairing/payload_mounter.go b/server/pairing/payload_mounter.go index db87d0234..4fc2c9451 100644 --- a/server/pairing/payload_mounter.go +++ b/server/pairing/payload_mounter.go @@ -170,7 +170,7 @@ func NewRawMessageLoader(backend *api.GethStatusBackend, payload *RawMessagesPay } func (r *RawMessageLoader) Load() (err error) { - r.payload.rawMessages, r.payload.subAccounts, r.payload.setting, err = r.syncRawMessageHandler.PrepareRawMessage(r.keyUID, r.deviceType) + r.payload.rawMessages, r.payload.profileKeypair, r.payload.setting, err = r.syncRawMessageHandler.PrepareRawMessage(r.keyUID, r.deviceType) return err } diff --git a/server/pairing/raw_message_handler.go b/server/pairing/raw_message_handler.go index 507837a57..2acffa5ab 100644 --- a/server/pairing/raw_message_handler.go +++ b/server/pairing/raw_message_handler.go @@ -37,7 +37,7 @@ func (s *SyncRawMessageHandler) CollectInstallationData(rawMessageCollector *Raw return err } -func (s *SyncRawMessageHandler) PrepareRawMessage(keyUID, deviceType string) (rm []*protobuf.RawMessage, as []*accounts.Account, syncSettings *settings.Settings, err error) { +func (s *SyncRawMessageHandler) PrepareRawMessage(keyUID, deviceType string) (rm []*protobuf.RawMessage, kp *accounts.Keypair, syncSettings *settings.Settings, err error) { syncSettings = new(settings.Settings) messenger := s.backend.Messenger() if messenger == nil { @@ -72,7 +72,7 @@ func (s *SyncRawMessageHandler) PrepareRawMessage(keyUID, deviceType string) (rm accountService := s.backend.StatusNode().AccountService() - as, err = accountService.GetAccountsByKeyUID(keyUID) + kp, err = accountService.GetKeypairByKeyUID(keyUID) if err != nil { return } @@ -104,7 +104,7 @@ func (s *SyncRawMessageHandler) HandleRawMessage(accountPayload *AccountPayload, rmp.setting.InstallationID = nodeConfig.ShhextConfig.InstallationID rmp.setting.CurrentNetwork = settingCurrentNetwork - err = s.backend.StartNodeWithAccountAndInitialConfig(*account, accountPayload.password, *rmp.setting, nodeConfig, rmp.subAccounts) + err = s.backend.StartNodeWithAccountAndInitialConfig(*account, accountPayload.password, *rmp.setting, nodeConfig, rmp.profileKeypair.Accounts) } if err != nil { return err diff --git a/services/accounts/accounts.go b/services/accounts/accounts.go index 73299e2b4..d429b73f1 100644 --- a/services/accounts/accounts.go +++ b/services/accounts/accounts.go @@ -13,7 +13,6 @@ import ( "github.com/status-im/status-go/account" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/multiaccounts/accounts" - "github.com/status-im/status-go/multiaccounts/keycards" "github.com/status-im/status-go/params" "github.com/status-im/status-go/protocol" ) @@ -40,7 +39,7 @@ type DerivedAddress struct { func (api *API) SaveAccount(ctx context.Context, account *accounts.Account) error { log.Info("[AccountsAPI::SaveAccount]") - err := (*api.messenger).SaveAccount(account) + err := (*api.messenger).SaveOrUpdateAccount(account) if err != nil { return err } @@ -48,36 +47,37 @@ func (api *API) SaveAccount(ctx context.Context, account *accounts.Account) erro return nil } -func (api *API) checkDerivedFromField(accounts []*accounts.Account) ([]*accounts.Account, error) { - for i := range accounts { - account := accounts[i] - if account.Wallet && account.DerivedFrom == "" { - address, err := api.db.GetWalletRootAddress() - if err != nil { - return nil, err - } - account.DerivedFrom = address.Hex() - } +// Setting `Keypair` without `Accounts` will update keypair only. +func (api *API) SaveKeypair(ctx context.Context, keypair *accounts.Keypair) error { + log.Info("[AccountsAPI::SaveKeypair]") + err := (*api.messenger).SaveOrUpdateKeypair(keypair) + if err != nil { + return err } - return accounts, nil + for _, acc := range keypair.Accounts { + api.feed.Send([]*accounts.Account{acc}) + } + return nil } func (api *API) GetAccounts(ctx context.Context) ([]*accounts.Account, error) { - accounts, err := api.db.GetAccounts() - if err != nil { - return nil, err - } - - return api.checkDerivedFromField(accounts) + return api.db.GetAccounts() } -func (api *API) GetAccountsByKeyUID(ctx context.Context, keyUID string) ([]*accounts.Account, error) { - accounts, err := api.db.GetAccountsByKeyUID(keyUID) - if err != nil { - return nil, err - } +func (api *API) GetWatchOnlyAccounts(ctx context.Context) ([]*accounts.Account, error) { + return api.db.GetWatchOnlyAccounts() +} - return api.checkDerivedFromField(accounts) +func (api *API) GetKeypairs(ctx context.Context) ([]*accounts.Keypair, error) { + return api.db.GetKeypairs() +} + +func (api *API) GetAccountByAddress(ctx context.Context, address types.Address) (*accounts.Account, error) { + return api.db.GetAccountByAddress(address) +} + +func (api *API) GetKeypairByKeyUID(ctx context.Context, keyUID string) (*accounts.Keypair, error) { + return api.db.GetKeypairByKeyUID(keyUID) } func (api *API) DeleteAccount(ctx context.Context, address types.Address) error { @@ -86,13 +86,14 @@ func (api *API) DeleteAccount(ctx context.Context, address types.Address) error return err } - allAccountsOfKeypairWithKeyUID, err := api.db.GetAccountsByKeyUID(acc.KeyUID) - if err != nil { - return err - } - lastAcccountOfKeypairWithTheSameKey := len(allAccountsOfKeypairWithKeyUID) == 1 - if acc.Type != accounts.AccountTypeWatch { + kp, err := api.db.GetKeypairByKeyUID(acc.KeyUID) + if err != nil { + return err + } + + lastAcccountOfKeypairWithTheSameKey := len(kp.Accounts) == 1 + knownKeycardsForKeyUID, err := api.db.GetKeycardByKeyUID(acc.KeyUID) if err != nil { return err @@ -107,7 +108,7 @@ func (api *API) DeleteAccount(ctx context.Context, address types.Address) error if acc.Type != accounts.AccountTypeKey { if lastAcccountOfKeypairWithTheSameKey { - err = api.manager.DeleteAccount(types.Address(common.HexToAddress(acc.DerivedFrom))) + err = api.manager.DeleteAccount(types.Address(common.HexToAddress(kp.DerivedFrom))) var e *account.ErrCannotLocateKeyFile if err != nil && !errors.As(err, &e) { return err @@ -137,9 +138,62 @@ func (api *API) DeleteAccount(ctx context.Context, address types.Address) error return (*api.messenger).DeleteAccount(address) } -func (api *API) AddAccount(ctx context.Context, password string, account *accounts.Account) error { +func (api *API) AddKeypair(ctx context.Context, password string, keypair *accounts.Keypair) error { + if len(keypair.KeyUID) == 0 { + return errors.New("`KeyUID` field of a keypair must be set") + } + + if len(keypair.Name) == 0 { + return errors.New("`Name` field of a keypair must be set") + } + + if len(keypair.Type) == 0 { + return errors.New("`Type` field of a keypair must be set") + } + + if keypair.Type != accounts.KeypairTypeKey { + if len(keypair.DerivedFrom) == 0 { + return errors.New("`DerivedFrom` field of a keypair must be set") + } + } + + for _, acc := range keypair.Accounts { + if acc.KeyUID != keypair.KeyUID { + return errors.New("all accounts of a keypair must have the same `KeyUID` as keypair key uid") + } + + err := api.checkAccountValidity(acc) + if err != nil { + return err + } + } + + err := api.SaveKeypair(ctx, keypair) + if err != nil { + return err + } + + if len(password) > 0 { + for _, acc := range keypair.Accounts { + if acc.Type == accounts.AccountTypeGenerated || acc.Type == accounts.AccountTypeSeed { + err = api.createKeystoreFileForAccount(keypair.DerivedFrom, password, acc) + if err != nil { + return err + } + } + } + } + + return nil +} + +func (api *API) checkAccountValidity(account *accounts.Account) error { if len(account.Address) == 0 { - return errors.New("`Address` field must be set") + return errors.New("`Address` field of an account must be set") + } + + if len(account.Type) == 0 { + return errors.New("`Type` field of an account must be set") } if account.Wallet || account.Chat { @@ -147,38 +201,30 @@ func (api *API) AddAccount(ctx context.Context, password string, account *accoun } if len(account.Name) == 0 { - return errors.New("`Name` field must be set") + return errors.New("`Name` field of an account must be set") } if len(account.Emoji) == 0 { - return errors.New("`Emoji` field must be set") + return errors.New("`Emoji` field of an account must be set") } if len(account.Color) == 0 { - return errors.New("`Color` field must be set") + return errors.New("`Color` field of an account must be set") } if account.Type != accounts.AccountTypeWatch { if len(account.KeyUID) == 0 { - return errors.New("`KeyUID` field must be set") + return errors.New("`KeyUID` field of an account must be set") } if len(account.PublicKey) == 0 { - return errors.New("`PublicKey` field must be set") - } - - if len(account.KeypairName) == 0 { - return errors.New("`KeypairName` field must be set") + return errors.New("`PublicKey` field of an account must be set") } if account.Type != accounts.AccountTypeKey { - if len(account.DerivedFrom) == 0 { - return errors.New("`DerivedFrom` field must be set") - } - if len(account.Path) == 0 { - return errors.New("`Path` field must be set") + return errors.New("`Path` field of an account must be set") } } } @@ -192,17 +238,51 @@ func (api *API) AddAccount(ctx context.Context, password string, account *accoun return errors.New("account already exists") } - // we need to create local keystore file only if password is provided and the account is being added is of - // "generated" or "seed" type. - if (account.Type == accounts.AccountTypeGenerated || account.Type == accounts.AccountTypeSeed) && len(password) > 0 { - info, err := api.manager.AccountsGenerator().LoadAccount(account.DerivedFrom, password) + return nil +} + +func (api *API) createKeystoreFileForAccount(masterAddress string, password string, account *accounts.Account) error { + if account.Type != accounts.AccountTypeGenerated && account.Type != accounts.AccountTypeSeed { + return errors.New("cannot create keystore file if account is not of `generated` or `seed` type") + } + if masterAddress == "" { + return errors.New("cannot create keystore file if master address is empty") + } + if password == "" { + return errors.New("cannot create keystore file if password is empty") + } + + info, err := api.manager.AccountsGenerator().LoadAccount(masterAddress, password) + if err != nil { + return err + } + + _, err = api.manager.AccountsGenerator().StoreDerivedAccounts(info.ID, password, []string{account.Path}) + return err +} + +func (api *API) AddAccount(ctx context.Context, password string, account *accounts.Account) error { + err := api.checkAccountValidity(account) + if err != nil { + return err + } + + if account.Type != accounts.AccountTypeWatch { + kp, err := api.db.GetKeypairByKeyUID(account.KeyUID) if err != nil { + if err == accounts.ErrDbKeypairNotFound { + return errors.New("cannot add an account for an unknown keypair") + } return err } - _, err = api.manager.AccountsGenerator().StoreDerivedAccounts(info.ID, password, []string{account.Path}) - if err != nil { - return err + // we need to create local keystore file only if password is provided and the account is being added is of + // "generated" or "seed" type. + if (account.Type == accounts.AccountTypeGenerated || account.Type == accounts.AccountTypeSeed) && len(password) > 0 { + err = api.createKeystoreFileForAccount(kp.DerivedFrom, password, account) + if err != nil { + return err + } } } @@ -216,12 +296,12 @@ func (api *API) ImportPrivateKey(ctx context.Context, privateKey string, passwor return err } - accs, err := api.db.GetAccountsByKeyUID(info.KeyUID) - if err != nil { + kp, err := api.db.GetKeypairByKeyUID(info.KeyUID) + if err != nil && err != accounts.ErrDbKeypairNotFound { return err } - if len(accs) > 0 { + if kp != nil { return errors.New("provided private key was already imported") } @@ -238,12 +318,12 @@ func (api *API) ImportMnemonic(ctx context.Context, mnemonic string, password st return err } - accs, err := api.db.GetAccountsByKeyUID(generatedAccountInfo.KeyUID) - if err != nil { + kp, err := api.db.GetKeypairByKeyUID(generatedAccountInfo.KeyUID) + if err != nil && err != accounts.ErrDbKeypairNotFound { return err } - if len(accs) > 0 { + if kp != nil { return errors.New("provided mnemonic was already imported, to add new account use `AddAccount` endpoint") } @@ -269,21 +349,22 @@ func (api *API) VerifyPassword(password string) bool { return api.VerifyKeystoreFileForAccount(address, password) } -func (api *API) AddKeycardOrAddAccountsIfKeycardIsAdded(ctx context.Context, kcUID string, kpName string, keyUID string, accountAddresses []string) error { +// 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 { - return errors.New("cannot migrate a keypair without any address") + return errors.New("cannot migrate a keypair without accounts") } - acc, err := api.db.GetAccountByAddress(types.Address(common.HexToAddress(accountAddresses[0]))) + kpDb, err := api.db.GetKeypairByKeyUID(keyUID) if err != nil { + if err == accounts.ErrDbKeypairNotFound { + return errors.New("cannot migrate an unknown keypair") + } return err } - if len(acc.DerivedFrom) == 0 { - return errors.New("an account being migrated doesn't contain `derived_from` field set") - } - - kp := keycards.Keycard{ + kp := accounts.Keycard{ KeycardUID: kcUID, KeycardName: kpName, KeycardLocked: false, @@ -304,20 +385,22 @@ func (api *API) AddKeycardOrAddAccountsIfKeycardIsAdded(ctx context.Context, kcU return err } - // 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 && acc.Type != accounts.AccountTypeWatch { - for _, addr := range kp.AccountsAddresses { - err = api.manager.DeleteAccount(addr) + 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 { + err = api.manager.DeleteAccount(addr) + if err != nil { + return err + } + } + + err = api.manager.DeleteAccount(types.Address(common.HexToAddress(kpDb.DerivedFrom))) if err != nil { return err } } - - err = api.manager.DeleteAccount(types.Address(common.HexToAddress(acc.DerivedFrom))) - if err != nil { - return err - } } return nil @@ -332,15 +415,15 @@ func (api *API) RemoveMigratedAccountsForKeycard(ctx context.Context, kcUID stri return (*api.messenger).RemoveMigratedAccountsForKeycard(ctx, kcUID, addresses, clock) } -func (api *API) GetAllKnownKeycards(ctx context.Context) ([]*keycards.Keycard, error) { +func (api *API) GetAllKnownKeycards(ctx context.Context) ([]*accounts.Keycard, error) { return api.db.GetAllKnownKeycards() } -func (api *API) GetAllKnownKeycardsGroupedByKeyUID(ctx context.Context) ([]*keycards.Keycard, error) { +func (api *API) GetAllKnownKeycardsGroupedByKeyUID(ctx context.Context) ([]*accounts.Keycard, error) { return api.db.GetAllKnownKeycardsGroupedByKeyUID() } -func (api *API) GetKeycardByKeyUID(ctx context.Context, keyUID string) ([]*keycards.Keycard, error) { +func (api *API) GetKeycardByKeyUID(ctx context.Context, keyUID string) ([]*accounts.Keycard, error) { return api.db.GetKeycardByKeyUID(keyUID) } diff --git a/services/accounts/service.go b/services/accounts/service.go index 24ebd157e..b308a1307 100644 --- a/services/accounts/service.go +++ b/services/accounts/service.go @@ -70,9 +70,9 @@ func (s *Service) Protocols() []p2p.Protocol { return nil } -func (s *Service) GetAccountsByKeyUID(keyUID string) ([]*accounts.Account, error) { +func (s *Service) GetKeypairByKeyUID(keyUID string) (*accounts.Keypair, error) { - return s.db.GetAccountsByKeyUID(keyUID) + return s.db.GetKeypairByKeyUID(keyUID) } func (s *Service) GetSettings() (settings.Settings, error) { diff --git a/services/ext/signal.go b/services/ext/signal.go index 6f6b849a6..677d5bc94 100644 --- a/services/ext/signal.go +++ b/services/ext/signal.go @@ -157,10 +157,14 @@ func (m *MessengerSignalsHandler) SendWakuBackedUpSettings(response *wakusync.Wa signal.SendWakuBackedUpSettings(response) } -func (m *MessengerSignalsHandler) SendWakuBackedUpWalletAccount(response *wakusync.WakuBackedUpDataResponse) { - signal.SendWakuBackedUpWalletAccount(response) +func (m *MessengerSignalsHandler) SendWakuBackedUpKeypair(response *wakusync.WakuBackedUpDataResponse) { + signal.SendWakuBackedUpKeypair(response) } func (m *MessengerSignalsHandler) SendWakuBackedUpKeycards(response *wakusync.WakuBackedUpDataResponse) { signal.SendWakuBackedUpKeycards(response) } + +func (m *MessengerSignalsHandler) SendWakuBackedUpWatchOnlyAccount(response *wakusync.WakuBackedUpDataResponse) { + signal.SendWakuBackedUpWatchOnlyAccount(response) +} diff --git a/services/wallet/api.go b/services/wallet/api.go index b37169685..2d5484904 100644 --- a/services/wallet/api.go +++ b/services/wallet/api.go @@ -53,6 +53,7 @@ func (api *API) GetCachedWalletTokensWithoutMarketData(ctx context.Context) (map type DerivedAddress struct { Address common.Address `json:"address"` + PublicKey types.HexBytes `json:"public-key,omitempty"` Path string `json:"path"` HasActivity bool `json:"hasActivity"` AlreadyCreated bool `json:"alreadyCreated"` @@ -458,8 +459,9 @@ func (api *API) getDerivedAddresses(id string, paths []string) ([]*DerivedAddres for accPath, acc := range info { derivedAddress := &DerivedAddress{ - Address: common.HexToAddress(acc.Address), - Path: accPath, + Address: common.HexToAddress(acc.Address), + PublicKey: types.Hex2Bytes(acc.PublicKey), + Path: accPath, } for _, account := range addedAccounts { diff --git a/services/web3provider/api_test.go b/services/web3provider/api_test.go index 81b7acfd2..e164592e3 100644 --- a/services/web3provider/api_test.go +++ b/services/web3provider/api_test.go @@ -79,7 +79,7 @@ func setupTestAPI(t *testing.T) (*API, func()) { accounts := []*accounts.Account{ {Address: types.HexToAddress(utils.TestConfig.Account1.WalletAddress), Chat: true, Wallet: true}, } - require.NoError(t, service.accountsDB.SaveAccounts(accounts)) + require.NoError(t, service.accountsDB.SaveOrUpdateAccounts(accounts)) require.NoError(t, service.accountsDB.CreateSettings(settings, *nodeConfig)) diff --git a/signal/events_sync_from_waku.go b/signal/events_sync_from_waku.go index 614b83730..cef552ad3 100644 --- a/signal/events_sync_from_waku.go +++ b/signal/events_sync_from_waku.go @@ -12,11 +12,14 @@ const ( // EventWakuBackedUpSettings is emitted while applying fetched settings from waku EventWakuBackedUpSettings = "waku.backedup.settings" - // EventWakuBackedUpWalletAccount is emitted while applying fetched wallet account data from waku - EventWakuBackedUpWalletAccount = "waku.backedup.wallet-account" // #nosec G101 + // EventWakuBackedUpKeypair is emitted while applying fetched keypair data from waku + EventWakuBackedUpKeypair = "waku.backedup.keypair" // EventWakuBackedUpKeycards is emitted while applying fetched keycard data from waku EventWakuBackedUpKeycards = "waku.backedup.keycards" + + // EventWakuBackedUpWatchOnlyAccount is emitted while applying fetched watch only account data from waku + EventWakuBackedUpWatchOnlyAccount = "waku.backedup.watch-only-account" // #nosec G101 ) func SendWakuFetchingBackupProgress(obj json.Marshaler) { @@ -31,10 +34,14 @@ func SendWakuBackedUpSettings(obj json.Marshaler) { send(EventWakuBackedUpSettings, obj) } -func SendWakuBackedUpWalletAccount(obj json.Marshaler) { - send(EventWakuBackedUpWalletAccount, obj) +func SendWakuBackedUpKeypair(obj json.Marshaler) { + send(EventWakuBackedUpKeypair, obj) } func SendWakuBackedUpKeycards(obj json.Marshaler) { send(EventWakuBackedUpKeycards, obj) } + +func SendWakuBackedUpWatchOnlyAccount(obj json.Marshaler) { + send(EventWakuBackedUpWatchOnlyAccount, obj) +}