From cf6ef3171a9dc60ba81538f9ab35646122680e01 Mon Sep 17 00:00:00 2001 From: Andrea Maria Piana Date: Thu, 25 Mar 2021 16:15:22 +0100 Subject: [PATCH] Add mailserver logic --- api/geth_backend.go | 4 + appdatabase/migrations/bindata.go | 78 +-- cmd/populate-db/.gitignore | 2 + cmd/populate-db/flags.go | 37 + cmd/populate-db/flags_test.go | 96 +++ cmd/populate-db/main.go | 460 +++++++++++++ cmd/populate-db/signing_phrase.go | 650 ++++++++++++++++++ cmd/populate-db/sync.go | 54 ++ mailserver/migrations/bindata.go | 6 +- multiaccounts/accounts/database.go | 9 + multiaccounts/migrations/bindata.go | 14 +- params/config.go | 10 + protocol/chat.go | 25 +- protocol/common/message.go | 15 +- protocol/contact.go | 2 +- protocol/encryption/migrations/migrations.go | 34 +- protocol/message_handler.go | 3 + protocol/message_persistence.go | 42 +- protocol/messenger.go | 125 +--- protocol/messenger_chats.go | 175 ++++- protocol/messenger_communities.go | 44 +- protocol/messenger_config.go | 9 +- protocol/messenger_contacts.go | 23 +- protocol/messenger_installations_test.go | 4 +- protocol/messenger_mailserver.go | 441 ++++++++++++ protocol/messenger_response.go | 59 +- protocol/messenger_test.go | 2 +- protocol/migrations/migrations.go | 86 ++- .../1619099821_add_last_synced_field.up.sql | 4 + protocol/persistence.go | 21 +- protocol/protobuf/chat_message.pb.go | 99 +-- protocol/protobuf/chat_message.proto | 2 + protocol/protobuf/enums.pb.go | 35 +- protocol/protobuf/enums.proto | 2 + .../migrations/migrations.go | 14 +- .../migrations/migrations.go | 10 +- protocol/requests/clear_history.go | 19 + protocol/requests/create_profile_chat.go | 19 + protocol/requests/create_public_chat.go | 19 + protocol/requests/deactivate_chat.go | 19 + protocol/transport/filters_manager.go | 35 +- protocol/transport/migrations/migrations.go | 6 +- .../transport/processed_message_ids_cache.go | 5 + protocol/transport/transport.go | 29 +- protocol/transport/waku/waku_service.go | 520 ++++++++++++++ .../whisper/migrations/migrations.go | 12 + protocol/transport/whisper/whisper_service.go | 525 ++++++++++++++ services/ext/api.go | 46 +- services/ext/service.go | 29 +- services/ext/signal.go | 9 +- signal/events_shhext.go | 11 - static/bindata.go | 28 +- t/bindata.go | 6 +- 53 files changed, 3531 insertions(+), 502 deletions(-) create mode 100644 cmd/populate-db/.gitignore create mode 100644 cmd/populate-db/flags.go create mode 100644 cmd/populate-db/flags_test.go create mode 100644 cmd/populate-db/main.go create mode 100644 cmd/populate-db/signing_phrase.go create mode 100644 cmd/populate-db/sync.go create mode 100644 protocol/messenger_mailserver.go create mode 100644 protocol/migrations/sqlite/1619099821_add_last_synced_field.up.sql create mode 100644 protocol/requests/clear_history.go create mode 100644 protocol/requests/create_profile_chat.go create mode 100644 protocol/requests/create_public_chat.go create mode 100644 protocol/requests/deactivate_chat.go create mode 100644 protocol/transport/waku/waku_service.go create mode 100644 protocol/transport/whisper/whisper_service.go diff --git a/api/geth_backend.go b/api/geth_backend.go index 4b95c833b..a1e7173d4 100644 --- a/api/geth_backend.go +++ b/api/geth_backend.go @@ -45,6 +45,7 @@ import ( "github.com/status-im/status-go/services/rpcstats" "github.com/status-im/status-go/services/subscriptions" "github.com/status-im/status-go/services/typeddata" + "github.com/status-im/status-go/services/wakuext" "github.com/status-im/status-go/services/wallet" "github.com/status-im/status-go/signal" "github.com/status-im/status-go/transactions" @@ -1158,6 +1159,9 @@ func (b *GethStatusBackend) GetActiveAccount() (*multiaccounts.Account, error) { return b.account, nil } +func (b *GethStatusBackend) WakuExtService() (*wakuext.Service, error) { + return b.statusNode.WakuExtService() +} func (b *GethStatusBackend) injectAccountsIntoServices() error { chatAccount, err := b.accountManager.SelectedChatAccount() diff --git a/appdatabase/migrations/bindata.go b/appdatabase/migrations/bindata.go index 1767eb5a9..13eac75f2 100644 --- a/appdatabase/migrations/bindata.go +++ b/appdatabase/migrations/bindata.go @@ -122,7 +122,7 @@ func _0001_appDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0001_app.down.sql", size: 356, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0001_app.down.sql", size: 356, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb5, 0x25, 0xa0, 0xf8, 0x7d, 0x2d, 0xd, 0xcf, 0x18, 0xe4, 0x73, 0xc3, 0x95, 0xf5, 0x24, 0x20, 0xa9, 0xe6, 0x9e, 0x1d, 0x93, 0xe5, 0xc5, 0xad, 0x93, 0x8f, 0x5e, 0x40, 0xb5, 0x30, 0xaa, 0x25}} return a, nil } @@ -142,7 +142,7 @@ func _0001_appUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0001_app.up.sql", size: 2967, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0001_app.up.sql", size: 2967, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf7, 0x3a, 0xa7, 0xf2, 0x8f, 0xfa, 0x82, 0x7c, 0xc5, 0x49, 0xac, 0xac, 0xf, 0xc, 0x77, 0xe2, 0xba, 0xe8, 0x4d, 0xe, 0x6f, 0x5d, 0x2c, 0x2c, 0x18, 0x80, 0xc2, 0x1d, 0xe, 0x25, 0xe, 0x18}} return a, nil } @@ -162,7 +162,7 @@ func _0002_tokensDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0002_tokens.down.sql", size: 19, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0002_tokens.down.sql", size: 19, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0x31, 0x2, 0xcc, 0x2f, 0x38, 0x90, 0xf7, 0x58, 0x37, 0x47, 0xf4, 0x18, 0xf7, 0x72, 0x74, 0x67, 0x14, 0x7e, 0xf3, 0xb1, 0xd6, 0x5f, 0xb0, 0xd5, 0xe7, 0x91, 0xf4, 0x26, 0x77, 0x8e, 0x68}} return a, nil } @@ -182,7 +182,7 @@ func _0002_tokensUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0002_tokens.up.sql", size: 248, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0002_tokens.up.sql", size: 248, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xcc, 0xd6, 0xde, 0xd3, 0x7b, 0xee, 0x92, 0x11, 0x38, 0xa4, 0xeb, 0x84, 0xca, 0xcb, 0x37, 0x75, 0x5, 0x77, 0x7f, 0x14, 0x39, 0xee, 0xa1, 0x8b, 0xd4, 0x5c, 0x6e, 0x55, 0x6, 0x50, 0x16, 0xd4}} return a, nil } @@ -202,7 +202,7 @@ func _0003_settingsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0003_settings.down.sql", size: 118, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0003_settings.down.sql", size: 118, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe5, 0xa6, 0xf5, 0xc0, 0x60, 0x64, 0x77, 0xe2, 0xe7, 0x3c, 0x9b, 0xb1, 0x52, 0xa9, 0x95, 0x16, 0xf8, 0x60, 0x2f, 0xa5, 0xeb, 0x46, 0xb9, 0xb9, 0x8f, 0x4c, 0xf4, 0xfd, 0xbb, 0xe7, 0xe5, 0xe5}} return a, nil } @@ -222,7 +222,7 @@ func _0003_settingsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0003_settings.up.sql", size: 1311, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0003_settings.up.sql", size: 1311, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x35, 0x0, 0xeb, 0xe2, 0x33, 0x68, 0xb9, 0xf4, 0xf6, 0x8e, 0x9e, 0x10, 0xe9, 0x58, 0x68, 0x28, 0xb, 0xcd, 0xec, 0x74, 0x71, 0xa7, 0x9a, 0x5a, 0x77, 0x59, 0xb1, 0x13, 0x1c, 0xa1, 0x5b}} return a, nil } @@ -242,7 +242,7 @@ func _0004_pending_stickersDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0004_pending_stickers.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0004_pending_stickers.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}} return a, nil } @@ -262,7 +262,7 @@ func _0004_pending_stickersUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0004_pending_stickers.up.sql", size: 61, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0004_pending_stickers.up.sql", size: 61, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3c, 0xed, 0x25, 0xdf, 0x75, 0x2, 0x6c, 0xf0, 0xa2, 0xa8, 0x37, 0x62, 0x65, 0xad, 0xfd, 0x98, 0xa0, 0x9d, 0x63, 0x94, 0xdf, 0x6b, 0x46, 0xe0, 0x68, 0xec, 0x9c, 0x7f, 0x77, 0xdd, 0xb3, 0x6}} return a, nil } @@ -282,7 +282,7 @@ func _0005_waku_modeDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0005_waku_mode.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0005_waku_mode.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}} return a, nil } @@ -302,7 +302,7 @@ func _0005_waku_modeUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0005_waku_mode.up.sql", size: 146, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0005_waku_mode.up.sql", size: 146, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa6, 0x91, 0xc, 0xd7, 0x89, 0x61, 0x2e, 0x4c, 0x5a, 0xb6, 0x67, 0xd1, 0xc1, 0x42, 0x24, 0x38, 0xd6, 0x1b, 0x75, 0x41, 0x9c, 0x23, 0xb0, 0xca, 0x5c, 0xf1, 0x5c, 0xd0, 0x13, 0x92, 0x3e, 0xe1}} return a, nil } @@ -322,7 +322,7 @@ func _0006_appearanceUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0006_appearance.up.sql", size: 67, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0006_appearance.up.sql", size: 67, mode: os.FileMode(0644), modTime: time.Unix(1609934130, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xae, 0x6, 0x25, 0x6c, 0xe4, 0x9d, 0xa7, 0x72, 0xe8, 0xbc, 0xe4, 0x1f, 0x1e, 0x2d, 0x7c, 0xb7, 0xf6, 0xa3, 0xec, 0x3b, 0x4e, 0x93, 0x2e, 0xa4, 0xec, 0x6f, 0xe5, 0x95, 0x94, 0xe8, 0x4, 0xfb}} return a, nil } @@ -342,7 +342,7 @@ func _0007_enable_waku_defaultUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0007_enable_waku_default.up.sql", size: 38, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0007_enable_waku_default.up.sql", size: 38, mode: os.FileMode(0644), modTime: time.Unix(1609934130, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd4, 0x42, 0xb6, 0xe5, 0x48, 0x41, 0xeb, 0xc0, 0x7e, 0x3b, 0xe6, 0x8e, 0x96, 0x33, 0x20, 0x92, 0x24, 0x5a, 0x60, 0xfa, 0xa0, 0x3, 0x5e, 0x76, 0x4b, 0x89, 0xaa, 0x37, 0x66, 0xbc, 0x26, 0x11}} return a, nil } @@ -362,7 +362,7 @@ func _0008_add_push_notificationsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0008_add_push_notifications.up.sql", size: 349, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0008_add_push_notifications.up.sql", size: 349, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5a, 0x0, 0xbf, 0xd0, 0xdd, 0xcd, 0x73, 0xe0, 0x7c, 0x56, 0xef, 0xdc, 0x57, 0x61, 0x94, 0x64, 0x70, 0xb9, 0xfa, 0xa1, 0x2a, 0x36, 0xc, 0x2f, 0xf8, 0x95, 0xa, 0x57, 0x3e, 0x7a, 0xd7, 0x12}} return a, nil } @@ -382,7 +382,7 @@ func _0009_enable_sending_push_notificationsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0009_enable_sending_push_notifications.down.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0009_enable_sending_push_notifications.down.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe9, 0xae, 0x1b, 0x41, 0xcb, 0x9c, 0x2c, 0x93, 0xc6, 0x2a, 0x77, 0x3, 0xb9, 0x51, 0xe0, 0x68, 0x68, 0x0, 0xf7, 0x5b, 0xb3, 0x1e, 0x94, 0x44, 0xba, 0x9c, 0xd0, 0x3b, 0x80, 0x21, 0x6f, 0xb5}} return a, nil } @@ -402,7 +402,7 @@ func _0009_enable_sending_push_notificationsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0009_enable_sending_push_notifications.up.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0009_enable_sending_push_notifications.up.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1b, 0x80, 0xe4, 0x9c, 0xc8, 0xb8, 0xd5, 0xef, 0xce, 0x74, 0x9b, 0x7b, 0xdd, 0xa, 0x99, 0x1e, 0xef, 0x7f, 0xb8, 0x99, 0x84, 0x4, 0x0, 0x6b, 0x1d, 0x2c, 0xa, 0xf8, 0x2c, 0x4f, 0xb5, 0x44}} return a, nil } @@ -422,7 +422,7 @@ func _0010_add_block_mentionsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0010_add_block_mentions.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0010_add_block_mentions.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6d, 0x9e, 0x27, 0x1e, 0xba, 0x9f, 0xca, 0xae, 0x98, 0x2e, 0x6e, 0xe3, 0xdd, 0xac, 0x73, 0x34, 0x4e, 0x69, 0x92, 0xb5, 0xf6, 0x9, 0xab, 0x50, 0x35, 0xd, 0xee, 0xeb, 0x3e, 0xcc, 0x7e, 0xce}} return a, nil } @@ -442,7 +442,7 @@ func _0010_add_block_mentionsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0010_add_block_mentions.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0010_add_block_mentions.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd7, 0x23, 0x85, 0xa2, 0xb5, 0xb6, 0xb4, 0x3f, 0xdc, 0x4e, 0xff, 0xe2, 0x6b, 0x66, 0x68, 0x5e, 0xb2, 0xb4, 0x14, 0xb2, 0x1b, 0x4d, 0xb1, 0xce, 0xf7, 0x6, 0x58, 0xa7, 0xaf, 0x93, 0x3f, 0x25}} return a, nil } @@ -462,7 +462,7 @@ func _0011_allow_webview_permission_requestsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0011_allow_webview_permission_requests.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0011_allow_webview_permission_requests.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}} return a, nil } @@ -482,7 +482,7 @@ func _0011_allow_webview_permission_requestsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0011_allow_webview_permission_requests.up.sql", size: 88, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0011_allow_webview_permission_requests.up.sql", size: 88, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x43, 0x5f, 0x22, 0x4c, 0x98, 0x1d, 0xc6, 0xf4, 0x89, 0xaf, 0xf4, 0x44, 0xba, 0xf8, 0x28, 0xa7, 0xb5, 0xb9, 0xf0, 0xf2, 0xcb, 0x5, 0x59, 0x7a, 0xc, 0xdf, 0xd3, 0x38, 0xa4, 0xb8, 0x98, 0xc2}} return a, nil } @@ -502,7 +502,7 @@ func _0012_pending_transactionsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0012_pending_transactions.down.sql", size: 33, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0012_pending_transactions.down.sql", size: 33, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7e, 0x41, 0xfe, 0x5c, 0xd8, 0xc3, 0x29, 0xfd, 0x31, 0x78, 0x99, 0x7a, 0xeb, 0x17, 0x62, 0x88, 0x41, 0xb3, 0xe7, 0xb5, 0x5, 0x0, 0x90, 0xa1, 0x7, 0x1a, 0x23, 0x88, 0x81, 0xba, 0x56, 0x9d}} return a, nil } @@ -522,7 +522,7 @@ func _0012_pending_transactionsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0012_pending_transactions.up.sql", size: 321, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0012_pending_transactions.up.sql", size: 321, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd, 0x17, 0xff, 0xd7, 0xa7, 0x49, 0x1e, 0x7b, 0x34, 0x63, 0x7c, 0x53, 0xaa, 0x6b, 0x2d, 0xc8, 0xe0, 0x82, 0x21, 0x90, 0x3a, 0x94, 0xf1, 0xa6, 0xe4, 0x70, 0xe5, 0x85, 0x1a, 0x48, 0x25, 0xb}} return a, nil } @@ -542,7 +542,7 @@ func _0013_favouritesDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0013_favourites.down.sql", size: 23, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0013_favourites.down.sql", size: 23, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x32, 0xf8, 0x55, 0x13, 0x4f, 0x4a, 0x19, 0x83, 0x9c, 0xda, 0x34, 0xb8, 0x3, 0x54, 0x82, 0x1e, 0x99, 0x36, 0x6b, 0x42, 0x3, 0xf6, 0x43, 0xde, 0xe6, 0x32, 0xb6, 0xdf, 0xe2, 0x59, 0x8c, 0x84}} return a, nil } @@ -562,7 +562,7 @@ func _0013_favouritesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0013_favourites.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0013_favourites.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbe, 0x1, 0x27, 0x38, 0x76, 0xf5, 0xcb, 0x61, 0xda, 0x5b, 0xce, 0xd9, 0x8b, 0x18, 0x77, 0x61, 0x84, 0xe7, 0x22, 0xe2, 0x13, 0x99, 0xab, 0x32, 0xbc, 0xbe, 0xed, 0x1f, 0x2f, 0xb0, 0xe4, 0x8d}} return a, nil } @@ -582,7 +582,7 @@ func _0014_add_use_mailserversDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0014_add_use_mailservers.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0014_add_use_mailservers.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}} return a, nil } @@ -602,7 +602,7 @@ func _0014_add_use_mailserversUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0014_add_use_mailservers.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0014_add_use_mailservers.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0xba, 0x65, 0xbf, 0x1b, 0xc9, 0x6d, 0x45, 0xf2, 0xf5, 0x30, 0x7c, 0xc1, 0xde, 0xb8, 0xe3, 0x3f, 0xa9, 0x2f, 0x9f, 0xea, 0x1, 0x29, 0x29, 0x65, 0xe7, 0x38, 0xab, 0xa4, 0x62, 0xf, 0xd0}} return a, nil } @@ -622,7 +622,7 @@ func _0015_link_previewsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0015_link_previews.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0015_link_previews.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}} return a, nil } @@ -642,7 +642,7 @@ func _0015_link_previewsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0015_link_previews.up.sql", size: 203, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0015_link_previews.up.sql", size: 203, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb1, 0xf7, 0x38, 0x25, 0xa6, 0xfc, 0x6b, 0x9, 0xe4, 0xd9, 0xbf, 0x58, 0x7b, 0x80, 0xd8, 0x48, 0x63, 0xde, 0xa5, 0x5e, 0x30, 0xa3, 0xeb, 0x68, 0x8e, 0x6a, 0x9f, 0xfd, 0xf4, 0x46, 0x41, 0x34}} return a, nil } @@ -662,7 +662,7 @@ func _0016_local_notifications_preferencesDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0016_local_notifications_preferences.down.sql", size: 43, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0016_local_notifications_preferences.down.sql", size: 43, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe0, 0x50, 0xc7, 0xdd, 0x53, 0x9c, 0x5d, 0x1e, 0xb5, 0x71, 0x25, 0x50, 0x58, 0xcf, 0x6d, 0xbe, 0x5a, 0x8, 0x12, 0xc9, 0x13, 0xd, 0x9a, 0x3d, 0x4b, 0x7a, 0x2f, 0x1b, 0xe5, 0x23, 0x52, 0x78}} return a, nil } @@ -682,7 +682,7 @@ func _0016_local_notifications_preferencesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0016_local_notifications_preferences.up.sql", size: 204, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0016_local_notifications_preferences.up.sql", size: 204, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3f, 0x3a, 0x16, 0x25, 0xdf, 0xba, 0x62, 0xd3, 0x81, 0x73, 0xc, 0x10, 0x85, 0xbc, 0x8d, 0xe, 0x1d, 0x62, 0xcb, 0xb, 0x6d, 0x8c, 0x4f, 0x63, 0x5f, 0xe2, 0xd, 0xc5, 0x46, 0xa8, 0x35, 0x5b}} return a, nil } @@ -702,7 +702,7 @@ func _0017_bookmarksDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0017_bookmarks.down.sql", size: 22, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0017_bookmarks.down.sql", size: 22, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9a, 0x13, 0x2a, 0x44, 0xb0, 0x3, 0x18, 0x63, 0xb8, 0x33, 0xda, 0x3a, 0xeb, 0xb8, 0xcb, 0xd1, 0x98, 0x29, 0xa7, 0xf0, 0x6, 0x9d, 0xc9, 0x62, 0xe7, 0x89, 0x7f, 0x77, 0xaf, 0xec, 0x6b, 0x8f}} return a, nil } @@ -722,7 +722,7 @@ func _0017_bookmarksUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0017_bookmarks.up.sql", size: 147, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0017_bookmarks.up.sql", size: 147, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbc, 0x47, 0xe1, 0xe3, 0xd8, 0xc6, 0x4, 0x6d, 0x5f, 0x2f, 0xa, 0x51, 0xa6, 0x8c, 0x6a, 0xe0, 0x3d, 0x8c, 0x91, 0x47, 0xbc, 0x1, 0x75, 0x46, 0x92, 0x2, 0x18, 0x6e, 0xe3, 0x4f, 0x18, 0x57}} return a, nil } @@ -742,7 +742,7 @@ func _0018_profile_pictures_visibilityUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0018_profile_pictures_visibility.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "0018_profile_pictures_visibility.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0xe3, 0xc5, 0xec, 0x83, 0x55, 0x45, 0x57, 0x7a, 0xaa, 0xd2, 0xa7, 0x59, 0xa7, 0x87, 0xef, 0x63, 0x19, 0x9c, 0x46, 0x9c, 0xc5, 0x32, 0x89, 0xa4, 0x68, 0x70, 0xd8, 0x83, 0x43, 0xa4, 0x72}} return a, nil } @@ -762,7 +762,7 @@ func _0019_blocks_ranges_extra_dataUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0019_blocks_ranges_extra_data.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1616402204, 0)} + info := bindataFileInfo{name: "0019_blocks_ranges_extra_data.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa3, 0x96, 0x32, 0x58, 0xf0, 0xb9, 0xe1, 0x70, 0x81, 0xca, 0x8d, 0x45, 0x57, 0x8a, 0x7, 0x5d, 0x9e, 0x2a, 0x30, 0xb, 0xad, 0x5f, 0xf8, 0xd4, 0x30, 0x94, 0x73, 0x37, 0x8d, 0xc1, 0x9a, 0xed}} return a, nil } @@ -782,7 +782,7 @@ func _0020_metricsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0020_metrics.up.sql", size: 235, mode: os.FileMode(0644), modTime: time.Unix(1616402204, 0)} + info := bindataFileInfo{name: "0020_metrics.up.sql", size: 235, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe8, 0x32, 0xbc, 0xb6, 0x9b, 0x5a, 0x8f, 0x9f, 0x4c, 0x90, 0x81, 0x3e, 0x2e, 0xd1, 0x23, 0xcd, 0xf1, 0x83, 0x35, 0xca, 0x66, 0x87, 0x52, 0x4e, 0x30, 0x3e, 0x4f, 0xa8, 0xfd, 0x30, 0x16, 0xbd}} return a, nil } @@ -802,7 +802,7 @@ func _0021_add_session_id_to_metricsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0021_add_session_id_to_metrics.up.sql", size: 55, mode: os.FileMode(0644), modTime: time.Unix(1619093832, 0)} + info := bindataFileInfo{name: "0021_add_session_id_to_metrics.up.sql", size: 55, mode: os.FileMode(0644), modTime: time.Unix(1618913882, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb7, 0x81, 0xfc, 0x97, 0xd1, 0x8b, 0xea, 0x8e, 0xd7, 0xc2, 0x53, 0x62, 0xe9, 0xbc, 0xf, 0x8c, 0x46, 0x41, 0x41, 0xb7, 0x6, 0x35, 0xf5, 0xba, 0xbb, 0x28, 0x50, 0x48, 0xbf, 0x36, 0x90, 0x5c}} return a, nil } @@ -822,7 +822,7 @@ func _0022_pending_transfersUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0022_pending_transfers.up.sql", size: 706, mode: os.FileMode(0644), modTime: time.Unix(1621327851, 0)} + info := bindataFileInfo{name: "0022_pending_transfers.up.sql", size: 706, mode: os.FileMode(0644), modTime: time.Unix(1621335496, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6a, 0x9, 0xe6, 0x6, 0xae, 0x60, 0xdd, 0xbb, 0x76, 0xac, 0xe0, 0x57, 0x30, 0x67, 0x37, 0x93, 0x40, 0x13, 0xec, 0xf2, 0x6e, 0x61, 0xa, 0x14, 0xb2, 0xb1, 0xbd, 0x91, 0xf8, 0x89, 0xb3, 0xe3}} return a, nil } @@ -842,7 +842,7 @@ func _1618237885_settings_anon_metrics_should_sendUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1618237885_settings_anon_metrics_should_send.up.sql", size: 80, mode: os.FileMode(0644), modTime: time.Unix(1619093832, 0)} + info := bindataFileInfo{name: "1618237885_settings_anon_metrics_should_send.up.sql", size: 80, mode: os.FileMode(0644), modTime: time.Unix(1618913882, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x6c, 0x1d, 0x1f, 0x54, 0x62, 0x18, 0x22, 0x5c, 0xa7, 0x8c, 0x59, 0x24, 0xd3, 0x4d, 0x55, 0xc4, 0x2a, 0x9e, 0x4c, 0x37, 0x6b, 0xfd, 0xac, 0xec, 0xb7, 0x68, 0x21, 0x26, 0x26, 0xf3, 0x92}} return a, nil } @@ -862,7 +862,7 @@ func _1618395756_contacts_onlyUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1618395756_contacts_only.up.sql", size: 136, mode: os.FileMode(0644), modTime: time.Unix(1619093832, 0)} + info := bindataFileInfo{name: "1618395756_contacts_only.up.sql", size: 136, mode: os.FileMode(0644), modTime: time.Unix(1618913882, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0xe3, 0xd0, 0xe7, 0xf2, 0x6e, 0xbf, 0x27, 0xf6, 0xe2, 0x2e, 0x16, 0x4b, 0x52, 0x3b, 0xcf, 0x63, 0x52, 0xfc, 0x1d, 0x43, 0xba, 0x42, 0xf9, 0x1e, 0x1e, 0x39, 0x40, 0xed, 0x0, 0x20, 0xa8}} return a, nil } @@ -882,7 +882,7 @@ func docGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 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 } diff --git a/cmd/populate-db/.gitignore b/cmd/populate-db/.gitignore new file mode 100644 index 000000000..647a4d420 --- /dev/null +++ b/cmd/populate-db/.gitignore @@ -0,0 +1,2 @@ +populate-db +tmp/ diff --git a/cmd/populate-db/flags.go b/cmd/populate-db/flags.go new file mode 100644 index 000000000..be519d51c --- /dev/null +++ b/cmd/populate-db/flags.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "os" + "path" + "strings" +) + +// configFlags represents an array of JSON configuration files passed to a command line utility +type configFlags []string + +func (f *configFlags) String() string { + return strings.Join(*f, ", ") +} + +func (f *configFlags) Set(value string) error { + if !path.IsAbs(value) { + // Convert to absolute path + cwd, err := os.Getwd() + if err != nil { + return err + } + value = path.Join(cwd, value) + } + + // Check that the file exists + stat, err := os.Stat(value) + if err != nil { + return err + } + if stat.IsDir() { + return fmt.Errorf("path does not represent a file: %s", value) + } + *f = append(*f, value) + return nil +} diff --git a/cmd/populate-db/flags_test.go b/cmd/populate-db/flags_test.go new file mode 100644 index 000000000..4331e1c73 --- /dev/null +++ b/cmd/populate-db/flags_test.go @@ -0,0 +1,96 @@ +package main + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/status-im/status-go/params" +) + +// nolint: deadcode +func TestStatusFlag(t *testing.T) { + service := "status" + + scenarios := []struct { + ipcEnabled bool + httpEnabled bool + flag string + err error + enabled bool + public bool + }{ + // no flags + {}, + // -status=ipc -ipc + { + ipcEnabled: true, + flag: "ipc", + enabled: true, + }, + // -status=http -http + { + httpEnabled: true, + flag: "http", + enabled: true, + public: true, + }, + // -status=ipc -http -ipc + { + httpEnabled: true, + ipcEnabled: true, + flag: "ipc", + enabled: true, + }, + // -http -ipc + { + httpEnabled: true, + ipcEnabled: true, + flag: "", + }, + // -status=ipc + { + err: errStatusServiceRequiresIPC, + flag: "ipc", + }, + // -status=http + { + err: errStatusServiceRequiresHTTP, + flag: "http", + }, + // -status=bad-value + { + err: errStatusServiceInvalidFlag, + flag: "bad-value", + }, + } + + for i, s := range scenarios { + msg := fmt.Sprintf("scenario %d", i) + + c, err := params.NewNodeConfig("", 0) + require.Nil(t, err, msg) + + c.IPCEnabled = s.ipcEnabled + c.HTTPEnabled = s.httpEnabled + + c, err = configureStatusService(s.flag, c) + + if s.err != nil { + require.Equal(t, s.err, err, msg) + require.Nil(t, c, msg) + continue + } + + require.Nil(t, err, msg) + require.Equal(t, s.enabled, c.EnableStatusService, msg) + + modules := c.FormatAPIModules() + if s.public { + require.Contains(t, modules, service, msg) + } else { + require.NotContains(t, modules, service, msg) + } + } +} diff --git a/cmd/populate-db/main.go b/cmd/populate-db/main.go new file mode 100644 index 000000000..661564903 --- /dev/null +++ b/cmd/populate-db/main.go @@ -0,0 +1,460 @@ +package main + +import ( + "context" + "encoding/json" + "errors" + "flag" + "fmt" + stdlog "log" + "math/rand" + "os" + "path/filepath" + "runtime" + + "strings" + "time" + + "github.com/google/uuid" + "golang.org/x/crypto/ssh/terminal" + + "github.com/ethereum/go-ethereum/log" + + "github.com/status-im/status-go/account/generator" + "github.com/status-im/status-go/api" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/multiaccounts" + "github.com/status-im/status-go/multiaccounts/accounts" + //"github.com/status-im/status-go/appdatabase" + //gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" + "github.com/status-im/status-go/eth-node/crypto" + "github.com/status-im/status-go/logutils" + "github.com/status-im/status-go/params" + "github.com/status-im/status-go/protocol" + "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/identity/alias" + wakuextn "github.com/status-im/status-go/services/wakuext" +) + +type testTimeSource struct{} + +func (t *testTimeSource) GetCurrentTime() uint64 { + return uint64(time.Now().Unix()) +} + +const ( + serverClientName = "Statusd" +) + +var ( + configFiles configFlags + logLevel = flag.String("log", "", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`) + logWithoutColors = flag.Bool("log-without-color", false, "Disables log colors") + ipcEnabled = flag.Bool("ipc", false, "Enable IPC RPC endpoint") + ipcFile = flag.String("ipcfile", "", "Set IPC file path") + seedPhrase = flag.String("seed-phrase", "", "Seed phrase") + pprofEnabled = flag.Bool("pprof", false, "Enable runtime profiling via pprof") + pprofPort = flag.Int("pprof-port", 52525, "Port for runtime profiling via pprof") + version = flag.Bool("version", false, "Print version and dump configuration") + nAddedContacts = flag.Int("added-contacts", 100, "Number of added contacts to create") + nContacts = flag.Int("contacts", 100, "Number of contacts to create") + nPublicChats = flag.Int("public-chats", 5, "Number of public chats") + nOneToOneChats = flag.Int("one-to-one-chats", 5, "Number of one to one chats") + + dataDir = flag.String("dir", getDefaultDataDir(), "Directory used by node to store data") + register = flag.Bool("register", false, "Register and make the node discoverable by other nodes") + networkID = flag.Int( + "network-id", + params.RopstenNetworkID, + fmt.Sprintf( + "A network ID: %d (Mainnet), %d (Ropsten), %d (Rinkeby), %d (Goerli)", + params.MainNetworkID, params.RopstenNetworkID, params.RinkebyNetworkID, params.GoerliNetworkID, + ), + ) + listenAddr = flag.String("addr", "", "address to bind listener to") + + syncAndExit = flag.Int("sync-and-exit", -1, "Timeout in minutes for blockchain sync and exit, zero means no timeout unless sync is finished") +) + +// All general log messages in this package should be routed through this logger. +var logger = log.New("package", "status-go/cmd/statusd") + +func init() { + flag.Var(&configFiles, "c", "JSON configuration file(s). Multiple configuration files can be specified, and will be merged in occurrence order") +} + +// nolint:gocyclo +func main() { + colors := terminal.IsTerminal(int(os.Stdin.Fd())) + if err := logutils.OverrideRootLog(true, "ERROR", logutils.FileOptions{}, colors); err != nil { + stdlog.Fatalf("Error initializing logger: %v", err) + } + + flag.Usage = printUsage + flag.Parse() + if flag.NArg() > 0 { + printUsage() + logger.Error("Extra args in command line: %v", flag.Args()) + os.Exit(1) + } + + opts := []params.Option{} + + config, err := params.NewNodeConfigWithDefaultsAndFiles( + *dataDir, + uint64(*networkID), + opts, + configFiles, + ) + if err != nil { + printUsage() + logger.Error(err.Error()) + os.Exit(1) + } + + // Use listenAddr if and only if explicitly provided in the arguments. + // The default value is set in params.NewNodeConfigWithDefaultsAndFiles(). + if *listenAddr != "" { + config.ListenAddr = *listenAddr + } + + // enable IPC RPC + if *ipcEnabled { + config.IPCEnabled = true + config.IPCFile = *ipcFile + } + + // set up logging options + setupLogging(config) + + // We want statusd to be distinct from StatusIM client. + config.Name = serverClientName + + if *version { + printVersion(config) + return + } + + backend := api.NewGethStatusBackend() + err = ImportAccount(*seedPhrase, backend) + if err != nil { + logger.Error("failed", "err", err) + return + } + + wakuextservice, err := backend.WakuExtService() + if err != nil { + logger.Error("failed", "err", err) + return + } + + wakuext := wakuextn.NewPublicAPI(wakuextservice) + + // This will start the push notification server as well as + // the config is set to Enabled + _, err = wakuext.StartMessenger() + if err != nil { + logger.Error("failed to start messenger", "error", err) + return + } + + logger.Info("Creating added contacts") + + for i := 0; i < *nAddedContacts; i++ { + key, err := crypto.GenerateKey() + if err != nil { + logger.Error("failed", err) + return + } + + keyString := common.PubkeyToHex(&key.PublicKey) + _, err = wakuext.AddContact(context.Background(), keyString) + if err != nil { + logger.Error("failed", "err", err) + return + } + } + + logger.Info("Creating contacts") + + for i := 0; i < *nContacts; i++ { + key, err := crypto.GenerateKey() + if err != nil { + return + } + + contact, err := protocol.BuildContactFromPublicKey(&key.PublicKey) + if err != nil { + return + } + + err = wakuext.SaveContact(context.Background(), contact) + if err != nil { + return + } + } + + logger.Info("Creating public chats") + + for i := 0; i < *nPublicChats; i++ { + chat := protocol.CreatePublicChat(randomString(10), &testTimeSource{}) + err = wakuext.SaveChat(context.Background(), chat) + if err != nil { + return + } + + } + + logger.Info("Creating one to one chats") + + for i := 0; i < *nOneToOneChats; i++ { + key, err := crypto.GenerateKey() + if err != nil { + return + } + + keyString := common.PubkeyToHex(&key.PublicKey) + chat := protocol.CreateOneToOneChat(keyString, &key.PublicKey, &testTimeSource{}) + err = wakuext.SaveChat(context.Background(), chat) + if err != nil { + return + } + + } + +} + +func getDefaultDataDir() string { + if home := os.Getenv("HOME"); home != "" { + return filepath.Join(home, ".statusd") + } + return "./statusd-data" +} + +func setupLogging(config *params.NodeConfig) { + if *logLevel != "" { + config.LogLevel = *logLevel + } + + colors := !(*logWithoutColors) && terminal.IsTerminal(int(os.Stdin.Fd())) + if err := logutils.OverrideRootLogWithConfig(config, colors); err != nil { + stdlog.Fatalf("Error initializing logger: %v", err) + } +} + +var ( + errStatusServiceRequiresIPC = errors.New("to enable the StatusService on IPC, -ipc flag must be set") + errStatusServiceRequiresHTTP = errors.New("to enable the StatusService on HTTP, -http flag must be set") + errStatusServiceInvalidFlag = errors.New("-status flag valid values are: ipc, http") +) + +// printVersion prints verbose output about version and config. +func printVersion(config *params.NodeConfig) { + fmt.Println(strings.Title(config.Name)) + fmt.Println("Version:", config.Version) + fmt.Println("Network ID:", config.NetworkID) + fmt.Println("Go Version:", runtime.Version()) + fmt.Println("OS:", runtime.GOOS) + fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) + fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) + + fmt.Println("Loaded Config: ", config) +} + +func printUsage() { + usage := ` +Usage: statusd [options] +Examples: + statusd # run regular Whisper node that joins Status network + statusd -c ./default.json # run node with configuration specified in ./default.json file + statusd -c ./default.json -c ./standalone.json # run node with configuration specified in ./default.json file, after merging ./standalone.json file + statusd -c ./default.json -metrics # run node with configuration specified in ./default.json file, and expose ethereum metrics with debug_metrics jsonrpc call + +Options: +` + fmt.Fprint(os.Stderr, usage) + flag.PrintDefaults() +} + +const pathWalletRoot = "m/44'/60'/0'/0" +const pathEIP1581 = "m/43'/60'/1581'" +const pathDefaultChat = pathEIP1581 + "/0'/0" +const pathDefaultWallet = pathWalletRoot + "/0" + +var paths = []string{pathWalletRoot, pathEIP1581, pathDefaultChat, pathDefaultWallet} + +func defaultSettings(generatedAccountInfo generator.GeneratedAccountInfo, derivedAddresses map[string]generator.AccountInfo, mnemonic *string) (*accounts.Settings, error) { + chatKeyString := derivedAddresses[pathDefaultChat].PublicKey + + settings := &accounts.Settings{} + settings.KeyUID = generatedAccountInfo.KeyUID + settings.Address = types.HexToAddress(generatedAccountInfo.Address) + settings.WalletRootAddress = types.HexToAddress(derivedAddresses[pathWalletRoot].Address) + + // Set chat key & name + name, err := alias.GenerateFromPublicKeyString(chatKeyString) + if err != nil { + return nil, err + } + settings.Name = name + settings.PublicKey = chatKeyString + + settings.DappsAddress = types.HexToAddress(derivedAddresses[pathDefaultWallet].Address) + settings.EIP1581Address = types.HexToAddress(derivedAddresses[pathEIP1581].Address) + settings.Mnemonic = mnemonic + + signingPhrase, err := buildSigningPhrase() + if err != nil { + return nil, err + } + settings.SigningPhrase = signingPhrase + + settings.SendPushNotifications = true + settings.InstallationID = uuid.New().String() + settings.UseMailservers = true + + settings.PreviewPrivacy = true + settings.Currency = "usd" + settings.ProfilePicturesVisibility = 1 + settings.LinkPreviewRequestEnabled = true + + visibleTokens := make(map[string][]string) + visibleTokens["mainnet"] = []string{"SNT"} + visibleTokensJSON, err := json.Marshal(visibleTokens) + if err != nil { + return nil, err + } + visibleTokenJSONRaw := json.RawMessage(visibleTokensJSON) + settings.WalletVisibleTokens = &visibleTokenJSONRaw + + // TODO: fix this + networks := make([]map[string]string, 0) + networksJSON, err := json.Marshal(networks) + if err != nil { + return nil, err + } + networkRawMessage := json.RawMessage(networksJSON) + settings.Networks = &networkRawMessage + settings.CurrentNetwork = "mainnet_rpc" + + return settings, nil +} + +func defaultNodeConfig(installationID string) (*params.NodeConfig, error) { + // Set mainnet + nodeConfig := ¶ms.NodeConfig{} + nodeConfig.NetworkID = 1 + nodeConfig.LogLevel = "ERROR" + nodeConfig.DataDir = "/ethereum/mainnet_rpc" + nodeConfig.UpstreamConfig = params.UpstreamRPCConfig{ + Enabled: true, + URL: "https://mainnet.infura.io/v3/800c641949d64d768a5070a1b0511938", + } + + nodeConfig.Name = "StatusIM" + nodeConfig.Rendezvous = true + clusterConfig, err := params.LoadClusterConfigFromFleet("eth.prod") + if err != nil { + return nil, err + } + nodeConfig.ClusterConfig = *clusterConfig + + nodeConfig.WalletConfig = params.WalletConfig{Enabled: true} + nodeConfig.LocalNotificationsConfig = params.LocalNotificationsConfig{Enabled: true} + nodeConfig.BrowsersConfig = params.BrowsersConfig{Enabled: true} + nodeConfig.PermissionsConfig = params.PermissionsConfig{Enabled: true} + nodeConfig.MailserversConfig = params.MailserversConfig{Enabled: true} + nodeConfig.EnableNTPSync = true + nodeConfig.WakuConfig = params.WakuConfig{ + Enabled: true, + LightClient: true, + MinimumPoW: 0.000001, + } + + nodeConfig.ShhextConfig = params.ShhextConfig{ + BackupDisabledDataDir: "", + InstallationID: installationID, + MaxMessageDeliveryAttempts: 6, + MailServerConfirmations: true, + VerifyTransactionURL: "", + VerifyENSURL: "", + VerifyENSContractAddress: "", + VerifyTransactionChainID: 1, + DataSyncEnabled: true, + PFSEnabled: true, + } + + // TODO: check topics + + return nodeConfig, nil +} + +func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error { + backend.UpdateRootDataDir("./tmp") + manager := backend.AccountManager() + manager.InitKeystore("./tmp") + err := backend.OpenAccounts() + if err != nil { + return err + } + generator := manager.AccountsGenerator() + generatedAccountInfo, err := generator.ImportMnemonic(seedPhrase, "") + if err != nil { + return err + } + + derivedAddresses, err := generator.DeriveAddresses(generatedAccountInfo.ID, paths) + if err != nil { + return err + } + + _, err = generator.StoreDerivedAccounts(generatedAccountInfo.ID, "", paths) + if err != nil { + return err + } + + account := multiaccounts.Account{ + KeyUID: generatedAccountInfo.KeyUID, + } + settings, err := defaultSettings(generatedAccountInfo, derivedAddresses, &seedPhrase) + if err != nil { + return err + } + + nodeConfig, err := defaultNodeConfig(settings.InstallationID) + if err != nil { + return err + } + + walletDerivedAccount := derivedAddresses[pathDefaultWallet] + walletAccount := accounts.Account{ + PublicKey: types.Hex2Bytes(walletDerivedAccount.PublicKey), + Address: types.HexToAddress(walletDerivedAccount.Address), + Color: "", + Wallet: true, + Path: pathDefaultWallet, + Name: "Ethereum account", + } + + chatDerivedAccount := derivedAddresses[pathDefaultChat] + chatAccount := accounts.Account{ + PublicKey: types.Hex2Bytes(chatDerivedAccount.PublicKey), + Address: types.HexToAddress(chatDerivedAccount.Address), + Name: settings.Name, + Chat: true, + Path: pathDefaultChat, + } + + accounts := []accounts.Account{walletAccount, chatAccount} + return backend.StartNodeWithAccountAndConfig(account, "", *settings, nodeConfig, accounts) +} + +var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func randomString(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letterRunes[rand.Intn(len(letterRunes))] + } + return string(b) +} diff --git a/cmd/populate-db/signing_phrase.go b/cmd/populate-db/signing_phrase.go new file mode 100644 index 000000000..42f45c745 --- /dev/null +++ b/cmd/populate-db/signing_phrase.go @@ -0,0 +1,650 @@ +package main + +import ( + "crypto/rand" + "math/big" +) + +func buildSigningPhrase() (string, error) { + length := big.NewInt(int64(len(dictionary))) + a, err := rand.Int(rand.Reader, length) + if err != nil { + return "", err + } + b, err := rand.Int(rand.Reader, length) + if err != nil { + return "", err + } + c, err := rand.Int(rand.Reader, length) + if err != nil { + return "", err + } + + return dictionary[a.Int64()] + " " + dictionary[b.Int64()] + " " + dictionary[c.Int64()], nil + +} + +var dictionary = []string{ + "acid", + "alto", + "apse", + "arch", + "area", + "army", + "atom", + "aunt", + "babe", + "baby", + "back", + "bail", + "bait", + "bake", + "ball", + "band", + "bank", + "barn", + "base", + "bass", + "bath", + "bead", + "beak", + "beam", + "bean", + "bear", + "beat", + "beef", + "beer", + "beet", + "bell", + "belt", + "bend", + "bike", + "bill", + "bird", + "bite", + "blow", + "blue", + "boar", + "boat", + "body", + "bolt", + "bomb", + "bone", + "book", + "boot", + "bore", + "boss", + "bowl", + "brow", + "bulb", + "bull", + "burn", + "bush", + "bust", + "cafe", + "cake", + "calf", + "call", + "calm", + "camp", + "cane", + "cape", + "card", + "care", + "carp", + "cart", + "case", + "cash", + "cast", + "cave", + "cell", + "cent", + "chap", + "chef", + "chin", + "chip", + "chop", + "chub", + "chug", + "city", + "clam", + "clef", + "clip", + "club", + "clue", + "coal", + "coat", + "code", + "coil", + "coin", + "coke", + "cold", + "colt", + "comb", + "cone", + "cook", + "cope", + "copy", + "cord", + "cork", + "corn", + "cost", + "crab", + "craw", + "crew", + "crib", + "crop", + "crow", + "curl", + "cyst", + "dame", + "dare", + "dark", + "dart", + "dash", + "data", + "date", + "dead", + "deal", + "dear", + "debt", + "deck", + "deep", + "deer", + "desk", + "dhow", + "diet", + "dill", + "dime", + "dirt", + "dish", + "disk", + "dock", + "doll", + "door", + "dory", + "drag", + "draw", + "drop", + "drug", + "drum", + "duck", + "dump", + "dust", + "duty", + "ease", + "east", + "eave", + "eddy", + "edge", + "envy", + "epee", + "exam", + "exit", + "face", + "fact", + "fail", + "fall", + "fame", + "fang", + "farm", + "fawn", + "fear", + "feed", + "feel", + "feet", + "file", + "fill", + "film", + "find", + "fine", + "fire", + "fish", + "flag", + "flat", + "flax", + "flow", + "foam", + "fold", + "font", + "food", + "foot", + "fork", + "form", + "fort", + "fowl", + "frog", + "fuel", + "full", + "gain", + "gale", + "galn", + "game", + "garb", + "gate", + "gear", + "gene", + "gift", + "girl", + "give", + "glad", + "glen", + "glue", + "glut", + "goal", + "goat", + "gold", + "golf", + "gong", + "good", + "gown", + "grab", + "gram", + "gray", + "grey", + "grip", + "grit", + "gyro", + "hail", + "hair", + "half", + "hall", + "hand", + "hang", + "harm", + "harp", + "hate", + "hawk", + "head", + "heat", + "heel", + "hell", + "helo", + "help", + "hemp", + "herb", + "hide", + "high", + "hill", + "hire", + "hive", + "hold", + "hole", + "home", + "hood", + "hoof", + "hook", + "hope", + "hops", + "horn", + "hose", + "host", + "hour", + "hunt", + "hurt", + "icon", + "idea", + "inch", + "iris", + "iron", + "item", + "jail", + "jeep", + "jeff", + "joey", + "join", + "joke", + "judo", + "jump", + "junk", + "jury", + "jute", + "kale", + "keep", + "kick", + "kill", + "kilt", + "kind", + "king", + "kiss", + "kite", + "knee", + "knot", + "lace", + "lack", + "lady", + "lake", + "lamb", + "lamp", + "land", + "lark", + "lava", + "lawn", + "lead", + "leaf", + "leek", + "lier", + "life", + "lift", + "lily", + "limo", + "line", + "link", + "lion", + "lisa", + "list", + "load", + "loaf", + "loan", + "lock", + "loft", + "long", + "look", + "loss", + "lout", + "love", + "luck", + "lung", + "lute", + "lynx", + "lyre", + "maid", + "mail", + "main", + "make", + "male", + "mall", + "manx", + "many", + "mare", + "mark", + "mask", + "mass", + "mate", + "math", + "meal", + "meat", + "meet", + "menu", + "mess", + "mice", + "midi", + "mile", + "milk", + "mime", + "mind", + "mine", + "mini", + "mint", + "miss", + "mist", + "moat", + "mode", + "mole", + "mood", + "moon", + "most", + "moth", + "move", + "mule", + "mutt", + "nail", + "name", + "neat", + "neck", + "need", + "neon", + "nest", + "news", + "node", + "nose", + "note", + "oboe", + "okra", + "open", + "oval", + "oven", + "oxen", + "pace", + "pack", + "page", + "pail", + "pain", + "pair", + "palm", + "pard", + "park", + "part", + "pass", + "past", + "path", + "peak", + "pear", + "peen", + "peer", + "pelt", + "perp", + "pest", + "pick", + "pier", + "pike", + "pile", + "pimp", + "pine", + "ping", + "pink", + "pint", + "pipe", + "piss", + "pith", + "plan", + "play", + "plot", + "plow", + "poem", + "poet", + "pole", + "polo", + "pond", + "pony", + "poof", + "pool", + "port", + "post", + "prow", + "pull", + "puma", + "pump", + "pupa", + "push", + "quit", + "race", + "rack", + "raft", + "rage", + "rail", + "rain", + "rake", + "rank", + "rate", + "read", + "rear", + "reef", + "rent", + "rest", + "rice", + "rich", + "ride", + "ring", + "rise", + "risk", + "road", + "robe", + "rock", + "role", + "roll", + "roof", + "room", + "root", + "rope", + "rose", + "ruin", + "rule", + "rush", + "ruth", + "sack", + "safe", + "sage", + "sail", + "sale", + "salt", + "sand", + "sari", + "sash", + "save", + "scow", + "seal", + "seat", + "seed", + "self", + "sell", + "shed", + "shin", + "ship", + "shoe", + "shop", + "shot", + "show", + "sick", + "side", + "sign", + "silk", + "sill", + "silo", + "sing", + "sink", + "site", + "size", + "skin", + "sled", + "slip", + "smog", + "snob", + "snow", + "soap", + "sock", + "soda", + "sofa", + "soft", + "soil", + "song", + "soot", + "sort", + "soup", + "spot", + "spur", + "stag", + "star", + "stay", + "stem", + "step", + "stew", + "stop", + "stud", + "suck", + "suit", + "swan", + "swim", + "tail", + "tale", + "talk", + "tank", + "tard", + "task", + "taxi", + "team", + "tear", + "teen", + "tell", + "temp", + "tent", + "term", + "test", + "text", + "thaw", + "tile", + "till", + "time", + "tire", + "toad", + "toga", + "togs", + "tone", + "tool", + "toot", + "tote", + "tour", + "town", + "tram", + "tray", + "tree", + "trim", + "trip", + "tuba", + "tube", + "tuna", + "tune", + "turn", + "tutu", + "twig", + "type", + "unit", + "user", + "vane", + "vase", + "vast", + "veal", + "veil", + "vein", + "vest", + "vibe", + "view", + "vise", + "wait", + "wake", + "walk", + "wall", + "wash", + "wasp", + "wave", + "wear", + "weed", + "week", + "well", + "west", + "whip", + "wife", + "will", + "wind", + "wine", + "wing", + "wire", + "wish", + "wolf", + "wood", + "wool", + "word", + "work", + "worm", + "wrap", + "wren", + "yard", + "yarn", + "yawl", + "year", + "yoga", + "yoke", + "yurt", + "zinc", + "zone", +} diff --git a/cmd/populate-db/sync.go b/cmd/populate-db/sync.go new file mode 100644 index 000000000..18658a3c8 --- /dev/null +++ b/cmd/populate-db/sync.go @@ -0,0 +1,54 @@ +package main + +import ( + "context" + "time" + + "github.com/status-im/status-go/node" +) + +func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc) { + if timeout == 0 { + return context.WithCancel(context.Background()) + } + + return context.WithTimeout(context.Background(), time.Duration(timeout)*time.Minute) +} + +// syncAndStopNode tries to sync the blockchain and stop the node. +// It returns an exit code (`0` if successful or `1` in case of error) +// that can be used in `os.Exit` to exit immediately when the function returns. +// The special exit code `-1` is used if execution was interrupted. +func syncAndStopNode(interruptCh <-chan struct{}, statusNode *node.StatusNode, timeout int) (exitCode int) { + + logger.Info("syncAndStopNode: node will synchronize the chain and exit", "timeoutInMins", timeout) + + ctx, cancel := createContextFromTimeout(timeout) + defer cancel() + + doneSync := make(chan struct{}) + errSync := make(chan error) + go func() { + if err := statusNode.EnsureSync(ctx); err != nil { + errSync <- err + } + close(doneSync) + }() + + select { + case err := <-errSync: + logger.Error("syncAndStopNode: failed to sync the chain", "error", err) + exitCode = 1 + case <-doneSync: + case <-interruptCh: + // cancel context and return immediately if interrupted + // `-1` is used as a special exit code to denote interruption + return -1 + } + + if err := statusNode.Stop(); err != nil { + logger.Error("syncAndStopNode: failed to stop the node", "error", err) + return 1 + } + return +} diff --git a/mailserver/migrations/bindata.go b/mailserver/migrations/bindata.go index 9f31e08b6..a6b468809 100644 --- a/mailserver/migrations/bindata.go +++ b/mailserver/migrations/bindata.go @@ -86,7 +86,7 @@ func _1557732988_initialize_dbDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1557732988_initialize_db.down.sql", size: 72, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1557732988_initialize_db.down.sql", size: 72, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0x40, 0x78, 0xb7, 0x71, 0x3c, 0x20, 0x3b, 0xc9, 0xb, 0x2f, 0x49, 0xe4, 0xff, 0x1c, 0x84, 0x54, 0xa1, 0x30, 0xe3, 0x90, 0xf8, 0x73, 0xda, 0xb0, 0x2a, 0xea, 0x8e, 0xf1, 0x82, 0xe7, 0xd2}} return a, nil } @@ -106,7 +106,7 @@ func _1557732988_initialize_dbUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1557732988_initialize_db.up.sql", size: 234, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1557732988_initialize_db.up.sql", size: 234, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8f, 0xa, 0x31, 0xf, 0x94, 0xe, 0xd7, 0xd6, 0xaa, 0x22, 0xd6, 0x6c, 0x7a, 0xbc, 0xad, 0x6a, 0xed, 0x2e, 0x7a, 0xf0, 0x24, 0x81, 0x87, 0x14, 0xe, 0x1c, 0x8a, 0xf1, 0x45, 0xaf, 0x9e, 0x85}} return a, nil } @@ -126,7 +126,7 @@ func staticGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static.go", size: 178, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "static.go", size: 178, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xab, 0x8a, 0xf4, 0x27, 0x24, 0x9d, 0x2a, 0x1, 0x7b, 0x54, 0xea, 0xae, 0x4a, 0x35, 0x40, 0x92, 0xb5, 0xf9, 0xb3, 0x54, 0x3e, 0x3a, 0x1a, 0x2b, 0xae, 0xfb, 0x9e, 0x82, 0xeb, 0x4c, 0xf, 0x6}} return a, nil } diff --git a/multiaccounts/accounts/database.go b/multiaccounts/accounts/database.go index c241bc3e4..f21b2eb5d 100644 --- a/multiaccounts/accounts/database.go +++ b/multiaccounts/accounts/database.go @@ -555,6 +555,15 @@ func (db *Database) GetNotificationsEnabled() (bool, error) { return result, err } +func (db *Database) GetUseMailservers() (bool, error) { + var result bool + err := db.db.QueryRow("SELECT use_mailservers FROM settings WHERE synthetic_id = 'id'").Scan(&result) + if err == sql.ErrNoRows { + return result, nil + } + return result, err +} + func (db *Database) GetMessagesFromContactsOnly() (bool, error) { var result bool err := db.db.QueryRow("SELECT messages_from_contacts_only FROM settings WHERE synthetic_id = 'id'").Scan(&result) diff --git a/multiaccounts/migrations/bindata.go b/multiaccounts/migrations/bindata.go index 7e31b03e1..e5dc39f99 100644 --- a/multiaccounts/migrations/bindata.go +++ b/multiaccounts/migrations/bindata.go @@ -90,7 +90,7 @@ func _0001_accountsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0x61, 0x4c, 0x18, 0xfc, 0xc, 0xdf, 0x5c, 0x1f, 0x5e, 0xd3, 0xbd, 0xfa, 0x12, 0x5e, 0x8d, 0x8d, 0x8b, 0xb9, 0x5f, 0x99, 0x46, 0x63, 0xa5, 0xe3, 0xa6, 0x8a, 0x4, 0xf1, 0x73, 0x8a, 0xe9}} return a, nil } @@ -110,7 +110,7 @@ func _0001_accountsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf2, 0xfa, 0x99, 0x8e, 0x96, 0xb3, 0x13, 0x6c, 0x1f, 0x6, 0x27, 0xc5, 0xd2, 0xd4, 0xe0, 0xa5, 0x26, 0x82, 0xa7, 0x26, 0xf2, 0x68, 0x9d, 0xed, 0x9c, 0x3d, 0xbb, 0xdc, 0x37, 0x28, 0xbc, 0x1}} return a, nil } @@ -130,7 +130,7 @@ func _1605007189_identity_imagesDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1605007189_identity_images.down.sql", size: 29, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1605007189_identity_images.down.sql", size: 29, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2f, 0xcf, 0xa7, 0xae, 0xd5, 0x4f, 0xcd, 0x14, 0x63, 0x9, 0xbe, 0x39, 0x49, 0x18, 0x96, 0xb2, 0xa3, 0x8, 0x7d, 0x41, 0xdb, 0x50, 0x5d, 0xf5, 0x4d, 0xa2, 0xd, 0x8f, 0x57, 0x79, 0x77, 0x67}} return a, nil } @@ -150,7 +150,7 @@ func _1605007189_identity_imagesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1605007189_identity_images.up.sql", size: 268, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1605007189_identity_images.up.sql", size: 268, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x50, 0xb6, 0xc1, 0x5c, 0x76, 0x72, 0x6b, 0x22, 0x34, 0xdc, 0x96, 0xdc, 0x2b, 0xfd, 0x2d, 0xbe, 0xcc, 0x1e, 0xd4, 0x5, 0x93, 0xd, 0xc2, 0x51, 0xf3, 0x1a, 0xef, 0x2b, 0x26, 0xa4, 0xeb, 0x65}} return a, nil } @@ -170,7 +170,7 @@ func _1606224181_drop_photo_path_from_accountsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.down.sql", size: 892, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.down.sql", size: 892, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x90, 0x24, 0x17, 0x7, 0x80, 0x93, 0x6f, 0x8d, 0x5d, 0xaa, 0x8c, 0x79, 0x15, 0x5d, 0xb3, 0x19, 0xd7, 0xd8, 0x39, 0xf9, 0x3a, 0x63, 0x8f, 0x81, 0x15, 0xb6, 0xd6, 0x9a, 0x37, 0xa8, 0x8e, 0x9b}} return a, nil } @@ -190,7 +190,7 @@ func _1606224181_drop_photo_path_from_accountsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.up.sql", size: 866, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.up.sql", size: 866, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xff, 0x4c, 0x97, 0xee, 0xef, 0x82, 0xb8, 0x6c, 0x71, 0xbb, 0x50, 0x7b, 0xe6, 0xd9, 0x22, 0x31, 0x7c, 0x1a, 0xfe, 0x91, 0x28, 0xf6, 0x6, 0x36, 0xe, 0xb1, 0xf1, 0xc8, 0x25, 0xac, 0x7e, 0xd6}} return a, nil } @@ -210,7 +210,7 @@ func docGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 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 } diff --git a/params/config.go b/params/config.go index 19e268370..2961a8e53 100644 --- a/params/config.go +++ b/params/config.go @@ -806,6 +806,16 @@ func NewConfigFromJSON(configJSON string) (*NodeConfig, error) { return config, nil } +func LoadClusterConfigFromFleet(fleet string) (*ClusterConfig, error) { + nodeConfig := &NodeConfig{} + err := loadConfigFromAsset(fmt.Sprintf("../config/cli/fleet-%s.json", fleet), nodeConfig) + if err != nil { + return nil, err + } + + return &nodeConfig.ClusterConfig, nil +} + func loadConfigFromJSON(configJSON string, nodeConfig *NodeConfig) error { decoder := json.NewDecoder(strings.NewReader(configJSON)) // override default configuration with values by JSON input diff --git a/protocol/chat.go b/protocol/chat.go index 155e3a260..cb38e26c4 100644 --- a/protocol/chat.go +++ b/protocol/chat.go @@ -35,6 +35,9 @@ const ( const pkStringLength = 68 +// timelineChatID is a magic constant id for your own timeline +const timelineChatID = "@timeline70bd746ddcc12beb96b2c9d572d0784ab137ffc774f5383e50585a932080b57cca0484b259e61cecbaa33a4c98a300a" + type Chat struct { // ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one // is the hex encoded public key and for group chats is a random uuid appended with @@ -84,6 +87,12 @@ type Chat struct { CommunityID string `json:"communityId,omitempty"` // Joined is a timestamp that indicates when the chat was joined Joined int64 `json:"joined,omitempty"` + + // SyncedTo is the time up until it has synced with a mailserver + SyncedTo uint32 `json:"syncedTo,omitempty"` + + // SyncedFrom is the time from when it was synced with a mailserver + SyncedFrom uint32 `json:"syncedFrom,omitempty"` } func (c *Chat) PublicKey() (*ecdsa.PublicKey, error) { @@ -348,7 +357,9 @@ func buildProfileChatID(publicKeyString string) string { return "@" + publicKeyString } -func CreateProfileChat(id string, profile string, timesource common.TimeSource) *Chat { +func CreateProfileChat(pubkey string, timesource common.TimeSource) *Chat { + + id := buildProfileChatID(pubkey) return &Chat{ ID: id, Name: id, @@ -356,7 +367,7 @@ func CreateProfileChat(id string, profile string, timesource common.TimeSource) Timestamp: int64(timesource.GetCurrentTime()), Color: chatColors[rand.Intn(len(chatColors))], // nolint: gosec ChatType: ChatTypeProfile, - Profile: profile, + Profile: pubkey, } } @@ -369,6 +380,16 @@ func CreateGroupChat(timesource common.TimeSource) Chat { } } +func CreateTimelineChat(timesource common.TimeSource) *Chat { + return &Chat{ + ID: timelineChatID, + Name: "#" + timelineChatID, + Timestamp: int64(timesource.GetCurrentTime()), + Active: true, + ChatType: ChatTypeTimeline, + } +} + func stringSliceToPublicKeys(slice []string) ([]*ecdsa.PublicKey, error) { result := make([]*ecdsa.PublicKey, len(slice)) for idx, item := range slice { diff --git a/protocol/common/message.go b/protocol/common/message.go index 61fb78903..898898747 100644 --- a/protocol/common/message.go +++ b/protocol/common/message.go @@ -69,6 +69,12 @@ type CommandParameters struct { Signature []byte `json:"signature"` } +// GapParameters is the From and To indicating the missing period in chat history +type GapParameters struct { + From uint32 `json:"from,omitempty"` + To uint32 `json:"to,omitempty"` +} + func (c *CommandParameters) IsTokenTransfer() bool { return len(c.Contract) != 0 } @@ -105,6 +111,9 @@ type Message struct { // CommandParameters is the parameters sent with the message CommandParameters *CommandParameters `json:"commandParameters"` + // GapParameters is the value from/to related to the gap + GapParameters *GapParameters `json:"gapParameters,omitempty"` + // Computed fields // RTL is whether this is a right-to-left message (arabic/hebrew script etc) RTL bool `json:"rtl"` @@ -169,8 +178,9 @@ func (m *Message) MarshalJSON() ([]byte, error) { Audio string `json:"audio,omitempty"` AudioDurationMs uint64 `json:"audioDurationMs,omitempty"` CommunityID string `json:"communityId,omitempty"` - Sticker *StickerAlias `json:"sticker"` - CommandParameters *CommandParameters `json:"commandParameters"` + Sticker *StickerAlias `json:"sticker,omitempty"` + CommandParameters *CommandParameters `json:"commandParameters,omitempty"` + GapParameters *GapParameters `json:"gapParameters,omitempty"` Timestamp uint64 `json:"timestamp"` ContentType protobuf.ChatMessage_ContentType `json:"contentType"` MessageType protobuf.MessageType `json:"messageType"` @@ -205,6 +215,7 @@ func (m *Message) MarshalJSON() ([]byte, error) { Links: m.Links, MessageType: m.MessageType, CommandParameters: m.CommandParameters, + GapParameters: m.GapParameters, } if sticker := m.GetSticker(); sticker != nil { item.Sticker = &StickerAlias{ diff --git a/protocol/contact.go b/protocol/contact.go index 1c392f239..a0285fa44 100644 --- a/protocol/contact.go +++ b/protocol/contact.go @@ -126,7 +126,7 @@ func buildContactFromPkString(pkString string) (*Contact, error) { return buildContact(pkString, publicKey) } -func buildContactFromPublicKey(publicKey *ecdsa.PublicKey) (*Contact, error) { +func BuildContactFromPublicKey(publicKey *ecdsa.PublicKey) (*Contact, error) { id := types.EncodeHex(crypto.FromECDSAPub(publicKey)) return buildContact(id, publicKey) } diff --git a/protocol/encryption/migrations/migrations.go b/protocol/encryption/migrations/migrations.go index 4d847867e..01aa7c0b5 100644 --- a/protocol/encryption/migrations/migrations.go +++ b/protocol/encryption/migrations/migrations.go @@ -100,7 +100,7 @@ func _1536754952_initial_schemaDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1536754952_initial_schema.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1536754952_initial_schema.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x44, 0xcf, 0x76, 0x71, 0x1f, 0x5e, 0x9a, 0x43, 0xd8, 0xcd, 0xb8, 0xc3, 0x70, 0xc3, 0x7f, 0xfc, 0x90, 0xb4, 0x25, 0x1e, 0xf4, 0x66, 0x20, 0xb8, 0x33, 0x7e, 0xb0, 0x76, 0x1f, 0xc, 0xc0, 0x75}} return a, nil } @@ -120,7 +120,7 @@ func _1536754952_initial_schemaUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1536754952_initial_schema.up.sql", size: 962, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1536754952_initial_schema.up.sql", size: 962, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x90, 0x5a, 0x59, 0x3e, 0x3, 0xe2, 0x3c, 0x81, 0x42, 0xcd, 0x4c, 0x9a, 0xe8, 0xda, 0x93, 0x2b, 0x70, 0xa4, 0xd5, 0x29, 0x3e, 0xd5, 0xc9, 0x27, 0xb6, 0xb7, 0x65, 0xff, 0x0, 0xcb, 0xde}} return a, nil } @@ -140,7 +140,7 @@ func _1539249977_update_ratchet_infoDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1539249977_update_ratchet_info.down.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1539249977_update_ratchet_info.down.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0xa4, 0xeb, 0xa0, 0xe6, 0xa0, 0xd4, 0x48, 0xbb, 0xad, 0x6f, 0x7d, 0x67, 0x8c, 0xbd, 0x25, 0xde, 0x1f, 0x73, 0x9a, 0xbb, 0xa8, 0xc9, 0x30, 0xb7, 0xa9, 0x7c, 0xaf, 0xb5, 0x1, 0x61, 0xdd}} return a, nil } @@ -160,7 +160,7 @@ func _1539249977_update_ratchet_infoUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1539249977_update_ratchet_info.up.sql", size: 368, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1539249977_update_ratchet_info.up.sql", size: 368, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x8e, 0xbf, 0x6f, 0xa, 0xc0, 0xe1, 0x3c, 0x42, 0x28, 0x88, 0x1d, 0xdb, 0xba, 0x1c, 0x83, 0xec, 0xba, 0xd3, 0x5f, 0x5c, 0x77, 0x5e, 0xa7, 0x46, 0x36, 0xec, 0x69, 0xa, 0x4b, 0x17, 0x79}} return a, nil } @@ -180,7 +180,7 @@ func _1540715431_add_versionDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1540715431_add_version.down.sql", size: 127, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1540715431_add_version.down.sql", size: 127, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x9, 0x4, 0xe3, 0x76, 0x2e, 0xb8, 0x9, 0x23, 0xf0, 0x70, 0x93, 0xc4, 0x50, 0xe, 0x9d, 0x84, 0x22, 0x8c, 0x94, 0xd3, 0x24, 0x9, 0x9a, 0xc1, 0xa1, 0x48, 0x45, 0xfd, 0x40, 0x6e, 0xe6}} return a, nil } @@ -200,7 +200,7 @@ func _1540715431_add_versionUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1540715431_add_version.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1540715431_add_version.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc7, 0x4c, 0x36, 0x96, 0xdf, 0x16, 0x10, 0xa6, 0x27, 0x1a, 0x79, 0x8b, 0x42, 0x83, 0x23, 0xc, 0x7e, 0xb6, 0x3d, 0x2, 0xda, 0xa4, 0xb4, 0xd, 0x27, 0x55, 0xba, 0xdc, 0xb2, 0x88, 0x8f, 0xa6}} return a, nil } @@ -220,7 +220,7 @@ func _1541164797_add_installationsDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1541164797_add_installations.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1541164797_add_installations.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0xfd, 0xe6, 0xd8, 0xca, 0x3b, 0x38, 0x18, 0xee, 0x0, 0x5f, 0x36, 0x9e, 0x1e, 0xd, 0x19, 0x3e, 0xb4, 0x73, 0x53, 0xe9, 0xa5, 0xac, 0xdd, 0xa1, 0x2f, 0xc7, 0x6c, 0xa8, 0xd9, 0xa, 0x88}} return a, nil } @@ -240,7 +240,7 @@ func _1541164797_add_installationsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1541164797_add_installations.up.sql", size: 216, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1541164797_add_installations.up.sql", size: 216, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2d, 0x18, 0x26, 0xb8, 0x88, 0x47, 0xdb, 0x83, 0xcc, 0xb6, 0x9d, 0x1c, 0x1, 0xae, 0x2f, 0xde, 0x97, 0x82, 0x3, 0x30, 0xa8, 0x63, 0xa1, 0x78, 0x4b, 0xa5, 0x9, 0x8, 0x75, 0xa2, 0x57, 0x81}} return a, nil } @@ -260,7 +260,7 @@ func _1558084410_add_secretDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1558084410_add_secret.down.sql", size: 56, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1558084410_add_secret.down.sql", size: 56, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x49, 0xb, 0x65, 0xdf, 0x59, 0xbf, 0xe9, 0x5, 0x5b, 0x6f, 0xd5, 0x3a, 0xb7, 0x57, 0xe8, 0x78, 0x38, 0x73, 0x53, 0x57, 0xf7, 0x24, 0x4, 0xe4, 0xa2, 0x49, 0x22, 0xa2, 0xc6, 0xfd, 0x80, 0xa4}} return a, nil } @@ -280,7 +280,7 @@ func _1558084410_add_secretUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1558084410_add_secret.up.sql", size: 301, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1558084410_add_secret.up.sql", size: 301, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x32, 0x36, 0x8e, 0x47, 0xb0, 0x8f, 0xc1, 0xc6, 0xf7, 0xc6, 0x9f, 0x2d, 0x44, 0x75, 0x2b, 0x26, 0xec, 0x6, 0xa0, 0x7b, 0xa5, 0xbd, 0xc8, 0x76, 0x8a, 0x82, 0x68, 0x2, 0x42, 0xb5, 0xf4}} return a, nil } @@ -300,7 +300,7 @@ func _1558588866_add_versionDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1558588866_add_version.down.sql", size: 47, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1558588866_add_version.down.sql", size: 47, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x52, 0x34, 0x3c, 0x46, 0x4a, 0xf0, 0x72, 0x47, 0x6f, 0x49, 0x5c, 0xc7, 0xf9, 0x32, 0xce, 0xc4, 0x3d, 0xfd, 0x61, 0xa1, 0x8b, 0x8f, 0xf2, 0x31, 0x34, 0xde, 0x15, 0x49, 0xa6, 0xde, 0xb9}} return a, nil } @@ -320,7 +320,7 @@ func _1558588866_add_versionUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2a, 0xea, 0x64, 0x39, 0x61, 0x20, 0x83, 0x83, 0xb, 0x2e, 0x79, 0x64, 0xb, 0x53, 0xfa, 0xfe, 0xc6, 0xf7, 0x67, 0x42, 0xd3, 0x4f, 0xdc, 0x7e, 0x30, 0x32, 0xe8, 0x14, 0x41, 0xe9, 0xe7, 0x3b}} return a, nil } @@ -340,7 +340,7 @@ func _1559627659_add_contact_codeDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1559627659_add_contact_code.down.sql", size: 32, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1559627659_add_contact_code.down.sql", size: 32, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5d, 0x64, 0x6d, 0xce, 0x24, 0x42, 0x20, 0x8d, 0x4f, 0x37, 0xaa, 0x9d, 0xc, 0x57, 0x98, 0xc1, 0xd1, 0x1a, 0x34, 0xcd, 0x9f, 0x8f, 0x34, 0x86, 0xb3, 0xd3, 0xdc, 0xf1, 0x7d, 0xe5, 0x1b, 0x6e}} return a, nil } @@ -360,7 +360,7 @@ func _1559627659_add_contact_codeUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1559627659_add_contact_code.up.sql", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1559627659_add_contact_code.up.sql", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x16, 0xf6, 0xc2, 0x62, 0x9c, 0xd2, 0xc9, 0x1e, 0xd8, 0xea, 0xaa, 0xea, 0x95, 0x8f, 0x89, 0x6a, 0x85, 0x5d, 0x9d, 0x99, 0x78, 0x3c, 0x90, 0x66, 0x99, 0x3e, 0x4b, 0x19, 0x62, 0xfb, 0x31, 0x4d}} return a, nil } @@ -380,7 +380,7 @@ func _1561368210_add_installation_metadataDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1561368210_add_installation_metadata.down.sql", size: 35, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1561368210_add_installation_metadata.down.sql", size: 35, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0xde, 0x3f, 0xd2, 0x4a, 0x50, 0x98, 0x56, 0xe3, 0xc0, 0xcd, 0x9d, 0xb0, 0x34, 0x3b, 0xe5, 0x62, 0x18, 0xb5, 0x20, 0xc9, 0x3e, 0xdc, 0x6a, 0x40, 0x36, 0x66, 0xea, 0x51, 0x8c, 0x71, 0xf5}} return a, nil } @@ -400,7 +400,7 @@ func _1561368210_add_installation_metadataUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1561368210_add_installation_metadata.up.sql", size: 267, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1561368210_add_installation_metadata.up.sql", size: 267, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb4, 0x71, 0x8f, 0x29, 0xb1, 0xaa, 0xd6, 0xd1, 0x8c, 0x17, 0xef, 0x6c, 0xd5, 0x80, 0xb8, 0x2c, 0xc3, 0xfe, 0xec, 0x24, 0x4d, 0xc8, 0x25, 0xd3, 0xb4, 0xcd, 0xa9, 0xac, 0x63, 0x61, 0xb2, 0x9c}} return a, nil } @@ -420,7 +420,7 @@ func docGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1603694100, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xef, 0xaf, 0xdf, 0xcf, 0x65, 0xae, 0x19, 0xfc, 0x9d, 0x29, 0xc1, 0x91, 0xaf, 0xb5, 0xd5, 0xb1, 0x56, 0xf3, 0xee, 0xa8, 0xba, 0x13, 0x65, 0xdb, 0xab, 0xcf, 0x4e, 0xac, 0x92, 0xe9, 0x60, 0xf1}} return a, nil } diff --git a/protocol/message_handler.go b/protocol/message_handler.go index 375bc78ad..5610a97d3 100644 --- a/protocol/message_handler.go +++ b/protocol/message_handler.go @@ -128,6 +128,9 @@ func (m *MessageHandler) HandleMembershipUpdate(messageState *ReceivedMessageSta // unless is coming from us or a contact isActive := messageState.CurrentMessageState.Contact.IsAdded() || messageState.CurrentMessageState.Contact.ID == ourKey newChat.Active = isActive + timestamp := uint32(newChat.Timestamp / 1000) + newChat.SyncedTo = timestamp + newChat.SyncedFrom = timestamp chat = &newChat } else { existingGroup, err := newProtocolGroupFromChat(chat) diff --git a/protocol/message_persistence.go b/protocol/message_persistence.go index 31445b9c0..2d9b95ce2 100644 --- a/protocol/message_persistence.go +++ b/protocol/message_persistence.go @@ -49,7 +49,9 @@ func (db sqlitePersistence) tableUserMessagesAllFields() string { replace_message, rtl, line_count, - response_to` + response_to, + gap_from, + gap_to` } func (db sqlitePersistence) tableUserMessagesAllFieldsJoin() string { @@ -87,6 +89,8 @@ func (db sqlitePersistence) tableUserMessagesAllFieldsJoin() string { m1.rtl, m1.line_count, m1.response_to, + m1.gap_from, + m1.gap_to, m2.source, m2.text, m2.parsed_text, @@ -119,6 +123,8 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message var alias sql.NullString var identicon sql.NullString var communityID sql.NullString + var gapFrom sql.NullInt64 + var gapTo sql.NullInt64 sticker := &protobuf.StickerMessage{} command := &common.CommandParameters{} @@ -159,6 +165,8 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message &message.RTL, &message.LineCount, &message.ResponseTo, + &gapFrom, + &gapTo, "edFrom, "edText, "edParsedText, @@ -188,6 +196,12 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message message.Alias = alias.String message.Identicon = identicon.String + if gapFrom.Valid && gapTo.Valid { + message.GapParameters = &common.GapParameters{ + From: uint32(gapFrom.Int64), + To: uint32(gapTo.Int64), + } + } if communityID.Valid { message.CommunityID = communityID.String } @@ -221,6 +235,8 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message } func (db sqlitePersistence) tableUserMessagesAllValues(message *common.Message) ([]interface{}, error) { + var gapFrom, gapTo uint32 + sticker := message.GetSticker() if sticker == nil { sticker = &protobuf.StickerMessage{} @@ -241,6 +257,11 @@ func (db sqlitePersistence) tableUserMessagesAllValues(message *common.Message) command = &common.CommandParameters{} } + if message.GapParameters != nil { + gapFrom = message.GapParameters.From + gapTo = message.GapParameters.To + } + var serializedMentions []byte var err error if len(message.Mentions) != 0 { @@ -297,6 +318,8 @@ func (db sqlitePersistence) tableUserMessagesAllValues(message *common.Message) message.RTL, message.LineCount, message.ResponseTo, + gapFrom, + gapTo, }, nil } @@ -967,6 +990,18 @@ func (db sqlitePersistence) DeleteMessage(id string) error { return err } +func (db sqlitePersistence) DeleteMessages(ids []string) error { + idsArgs := make([]interface{}, 0, len(ids)) + for _, id := range ids { + idsArgs = append(idsArgs, id) + } + inVector := strings.Repeat("?, ", len(ids)-1) + "?" + + _, err := db.db.Exec("DELETE FROM user_messages WHERE id IN ("+inVector+")", idsArgs...) // nolint: gosec + + return err +} + func (db sqlitePersistence) HideMessage(id string) error { _, err := db.db.Exec(`UPDATE user_messages SET hide = 1, seen = 1 WHERE id = ?`, id) return err @@ -1381,6 +1416,11 @@ func (db sqlitePersistence) clearHistory(chat *Chat, currentClockValue uint64, t chat.DeletedAtClockValue = currentClockValue } + // Reset synced-to/from + syncedTo := uint32(currentClockValue / 1000) + chat.SyncedTo = syncedTo + chat.SyncedFrom = syncedTo + chat.LastMessage = nil chat.UnviewedMessagesCount = 0 diff --git a/protocol/messenger.go b/protocol/messenger.go index 0240aecda..b55dd125d 100644 --- a/protocol/messenger.go +++ b/protocol/messenger.go @@ -445,21 +445,9 @@ func (m *Messenger) Start() (*MessengerResponse, error) { if err := m.cleanTopics(); err != nil { return nil, err } - response := &MessengerResponse{Filters: m.transport.Filters()} + response := &MessengerResponse{} if m.mailserversDatabase != nil { - mailserverTopics, err := m.mailserversDatabase.Topics() - if err != nil { - return nil, err - } - response.MailserverTopics = mailserverTopics - - mailserverRanges, err := m.mailserversDatabase.ChatRequestRanges() - if err != nil { - return nil, err - } - response.MailserverRanges = mailserverRanges - mailservers, err := m.mailserversDatabase.Mailservers() if err != nil { return nil, err @@ -757,10 +745,6 @@ func (m *Messenger) handleSharedSecrets(secrets []*sharedsecret.Secret) error { } result = append(result, filter) } - if m.config.onNegotiatedFilters != nil { - m.config.onNegotiatedFilters(result) - } - return nil } @@ -938,8 +922,6 @@ func (m *Messenger) handlePushNotificationClientRegistrations(c chan struct{}) { // Init analyzes chats and contacts in order to setup filters // which are responsible for retrieving messages. func (m *Messenger) Init() error { - m.mutex.Lock() - defer m.mutex.Unlock() // Seed the for color generation rand.Seed(time.Now().Unix()) @@ -951,6 +933,7 @@ func (m *Messenger) Init() error { publicKeys []*ecdsa.PublicKey ) + logger.Info("1") joinedCommunities, err := m.communitiesManager.Joined() if err != nil { return err @@ -975,6 +958,7 @@ func (m *Messenger) Init() error { if err != nil { return err } + logger.Info("2") // Get chat IDs and public keys from the existing chats. // TODO: Get only active chats by the query. @@ -982,6 +966,7 @@ func (m *Messenger) Init() error { if err != nil { return err } + logger.Info("3") for _, chat := range chats { if err := chat.Validate(); err != nil { logger.Warn("failed to validate chat", zap.Error(err)) @@ -1016,12 +1001,24 @@ func (m *Messenger) Init() error { return errors.New("invalid chat type") } } + // upsert timeline chat + err = m.ensureTimelineChat() + if err != nil { + return err + } + err = m.ensureMyOwnProfileChat() + if err != nil { + return err + } + // uspert profile chat + logger.Info("4") // Get chat IDs and public keys from the contacts. contacts, err := m.persistence.Contacts() if err != nil { return err } + logger.Info("5") for idx, contact := range contacts { m.allContacts.Store(contact.ID, contacts[idx]) // We only need filters for contacts added by us and not blocked. @@ -1035,6 +1032,7 @@ func (m *Messenger) Init() error { } publicKeys = append(publicKeys, publicKey) } + logger.Info("6") installations, err := m.encryptor.GetOurInstallations(&m.identity.PublicKey) if err != nil { @@ -1044,8 +1042,10 @@ func (m *Messenger) Init() error { for _, installation := range installations { m.allInstallations.Store(installation.ID, installation) } + logger.Info("7") _, err = m.transport.InitFilters(publicChatIDs, publicKeys) + logger.Info("8") return err } @@ -1148,29 +1148,6 @@ func (m *Messenger) Mailservers() ([]string, error) { return nil, ErrNotImplemented } -// This is not accurate, it should not leave transport on removal of chat/group -// only once there is no more: Group chat with that member, one-to-one chat, contact added by us -func (m *Messenger) Leave(chat Chat) error { - switch chat.ChatType { - case ChatTypeOneToOne: - pk, err := chat.PublicKey() - if err != nil { - return err - } - return m.transport.LeavePrivate(pk) - case ChatTypePrivateGroupChat: - members, err := chat.MembersAsPublicKeys() - if err != nil { - return err - } - return m.transport.LeaveGroup(members) - case ChatTypePublic, ChatTypeProfile, ChatTypeTimeline: - return m.transport.LeavePublic(chat.Name) - default: - return errors.New("chat is neither public nor private") - } -} - func (m *Messenger) CreateGroupChatWithMembers(ctx context.Context, name string, members []string) (*MessengerResponse, error) { var response MessengerResponse logger := m.logger.With(zap.String("site", "CreateGroupChatWithMembers")) @@ -1215,6 +1192,11 @@ func (m *Messenger) CreateGroupChatWithMembers(ctx context.Context, name string, return nil, err } + timestamp := uint32(chat.Timestamp / 1000) + + chat.SyncedTo = timestamp + chat.SyncedFrom = timestamp + m.allChats.Store(chat.ID, &chat) _, err = m.dispatchMessage(ctx, common.RawMessage{ @@ -2900,10 +2882,6 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte return true }) - for _, filter := range messageState.AllFilters { - messageState.Response.Filters = append(messageState.Response.Filters, filter) - } - // Hydrate chat alias and identicon for id := range messageState.Response.chats { chat, _ := messageState.AllChats.Load(id) @@ -3025,37 +3003,6 @@ func (m *Messenger) RequestHistoricMessages( return m.transport.SendMessagesRequest(ctx, m.mailserver, from, to, cursor, waitForResponse) } -func (m *Messenger) RequestHistoricMessagesForFilter( - ctx context.Context, - from, to uint32, - cursor []byte, - filter *transport.Filter, - waitForResponse bool, -) ([]byte, error) { - if m.mailserver == nil { - return nil, errors.New("no mailserver selected") - } - - return m.transport.SendMessagesRequestForFilter(ctx, m.mailserver, from, to, cursor, filter, waitForResponse) -} - -func (m *Messenger) LoadFilters(filters []*transport.Filter) ([]*transport.Filter, error) { - return m.transport.LoadFilters(filters) -} - -func (m *Messenger) RemoveFilters(filters []*transport.Filter) error { - return m.transport.RemoveFilters(filters) -} - -func (m *Messenger) ConfirmMessagesProcessed(messageIDs [][]byte) error { - for _, id := range messageIDs { - if err := m.encryptor.ConfirmMessageProcessed(id); err != nil { - return err - } - } - return nil -} - func (m *Messenger) MessageByID(id string) (*common.Message, error) { return m.persistence.MessageByID(id) } @@ -3098,30 +3045,6 @@ func (m *Messenger) DeleteMessagesByChatID(id string) error { return m.persistence.DeleteMessagesByChatID(id) } -func (m *Messenger) ClearHistory(id string) (*MessengerResponse, error) { - return m.clearHistory(id) -} - -func (m *Messenger) clearHistory(id string) (*MessengerResponse, error) { - chat, ok := m.allChats.Load(id) - if !ok { - return nil, ErrChatNotFound - } - - clock, _ := chat.NextClockAndTimestamp(m.transport) - - err := m.persistence.ClearHistory(chat, clock) - if err != nil { - return nil, err - } - - m.allChats.Store(id, chat) - - response := &MessengerResponse{} - response.AddChat(chat) - return response, nil -} - // MarkMessagesSeen marks messages with `ids` as seen in the chat `chatID`. // It returns the number of affected messages or error. If there is an error, // the number of affected messages is always zero. diff --git a/protocol/messenger_chats.go b/protocol/messenger_chats.go index 5d0794ff6..c80d1ce13 100644 --- a/protocol/messenger_chats.go +++ b/protocol/messenger_chats.go @@ -37,6 +37,78 @@ func (m *Messenger) ActiveChats() []*Chat { return chats } +func (m *Messenger) CreatePublicChat(request *requests.CreatePublicChat) (*MessengerResponse, error) { + if err := request.Validate(); err != nil { + return nil, err + } + + chatID := request.ID + + chat, ok := m.allChats.Load(chatID) + if !ok { + chat = CreatePublicChat(chatID, m.getTimesource()) + } + chat.Active = true + + // Save topics + _, err := m.Join(chat) + if err != nil { + return nil, err + } + + err = m.saveChat(chat) + if err != nil { + return nil, err + } + + response := &MessengerResponse{} + response.AddChat(chat) + + m.scheduleSyncChat(chat) + + return response, nil +} + +func (m *Messenger) CreateProfileChat(request *requests.CreateProfileChat) (*MessengerResponse, error) { + if err := request.Validate(); err != nil { + return nil, err + } + + publicKey, err := common.HexToPubkey(request.ID) + if err != nil { + return nil, err + } + + chat := m.buildProfileChat(request.ID) + + chat.Active = true + + // Save topics + _, err = m.Join(chat) + if err != nil { + return nil, err + } + + // Check contact code + filter, err := m.transport.JoinPrivate(publicKey) + if err != nil { + return nil, err + } + + err = m.saveChat(chat) + if err != nil { + return nil, err + } + + response := &MessengerResponse{} + response.AddChat(chat) + + m.scheduleSyncChat(chat) + m.scheduleSyncFilter(filter) + + return response, nil +} + func (m *Messenger) CreateOneToOneChat(request *requests.CreateOneToOneChat) (*MessengerResponse, error) { if err := request.Validate(); err != nil { return nil, err @@ -67,11 +139,11 @@ func (m *Messenger) CreateOneToOneChat(request *requests.CreateOneToOneChat) (*M // TODO(Samyoul) remove storing of an updated reference pointer? m.allChats.Store(chatID, chat) - response := &MessengerResponse{ - Filters: filters, - } + response := &MessengerResponse{} response.AddChat(chat) + m.scheduleSyncFilters(filters) + return response, nil } @@ -99,8 +171,12 @@ func (m *Messenger) SaveChat(chat *Chat) error { return m.saveChat(chat) } -func (m *Messenger) DeactivateChat(chatID string) (*MessengerResponse, error) { - return m.deactivateChat(chatID) +func (m *Messenger) DeactivateChat(request *requests.DeactivateChat) (*MessengerResponse, error) { + if err := request.Validate(); err != nil { + return nil, err + } + + return m.deactivateChat(request.ID) } func (m *Messenger) deactivateChat(chatID string) (*MessengerResponse, error) { @@ -125,6 +201,11 @@ func (m *Messenger) deactivateChat(chatID string) (*MessengerResponse, error) { if err != nil { return nil, err } + + err = m.transport.ClearProcessedMessageIDsCache() + if err != nil { + return nil, err + } } // TODO(samyoul) remove storing of an updated reference pointer? @@ -228,3 +309,87 @@ func (m *Messenger) Join(chat *Chat) ([]*transport.Filter, error) { return nil, errors.New("chat is neither public nor private") } } + +func (m *Messenger) buildProfileChat(id string) *Chat { + // Create the corresponding profile chat + profileChatID := buildProfileChatID(id) + profileChat, ok := m.allChats.Load(profileChatID) + + if !ok { + profileChat = CreateProfileChat(id, m.getTimesource()) + } + + return profileChat + +} + +func (m *Messenger) ensureTimelineChat() error { + chat, err := m.persistence.Chat(timelineChatID) + if err != nil { + return err + } + + if chat != nil { + return nil + } + + chat = CreateTimelineChat(m.getTimesource()) + m.allChats.Store(timelineChatID, chat) + return m.saveChat(chat) +} + +func (m *Messenger) ensureMyOwnProfileChat() error { + chatID := common.PubkeyToHex(&m.identity.PublicKey) + chat, ok := m.allChats.Load(chatID) + if ok { + return nil + } + + chat = m.buildProfileChat(chatID) + + chat.Active = true + + // Save topics + _, err := m.Join(chat) + if err != nil { + return err + } + + return m.saveChat(chat) +} + +func (m *Messenger) ClearHistory(request *requests.ClearHistory) (*MessengerResponse, error) { + if err := request.Validate(); err != nil { + return nil, err + } + + return m.clearHistory(request.ID) +} + +func (m *Messenger) clearHistory(id string) (*MessengerResponse, error) { + chat, ok := m.allChats.Load(id) + if !ok { + return nil, ErrChatNotFound + } + + clock, _ := chat.NextClockAndTimestamp(m.transport) + + err := m.persistence.ClearHistory(chat, clock) + if err != nil { + return nil, err + } + + if chat.Public() { + + err = m.transport.ClearProcessedMessageIDsCache() + if err != nil { + return nil, err + } + } + + m.allChats.Store(id, chat) + + response := &MessengerResponse{} + response.AddChat(chat) + return response, nil +} diff --git a/protocol/messenger_communities.go b/protocol/messenger_communities.go index 19e77aece..ac108b31c 100644 --- a/protocol/messenger_communities.go +++ b/protocol/messenger_communities.go @@ -134,8 +134,6 @@ func (m *Messenger) JoinedCommunities() ([]*communities.Community, error) { } func (m *Messenger) JoinCommunity(communityID types.HexBytes) (*MessengerResponse, error) { - m.mutex.Lock() - defer m.mutex.Unlock() return m.joinCommunity(communityID) } @@ -163,7 +161,8 @@ func (m *Messenger) joinCommunity(communityID types.HexBytes) (*MessengerRespons return nil, err } - response.Filters = filters + m.scheduleSyncFilters(filters) + response.AddCommunity(community) return response, m.saveChats(chats) @@ -250,8 +249,6 @@ func (m *Messenger) DeclineRequestToJoinCommunity(request *requests.DeclineReque } func (m *Messenger) LeaveCommunity(communityID types.HexBytes) (*MessengerResponse, error) { - m.mutex.Lock() - defer m.mutex.Unlock() return m.leaveCommunity(communityID) } @@ -273,25 +270,17 @@ func (m *Messenger) leaveCommunity(communityID types.HexBytes) (*MessengerRespon } response.AddRemovedChat(communityChatID) - filter, err := m.transport.RemoveFilterByChatID(communityChatID) + _, err = m.transport.RemoveFilterByChatID(communityChatID) if err != nil { return nil, err } - - if filter != nil { - response.RemovedFilters = append(response.RemovedFilters, filter) - } } - filter, err := m.transport.RemoveFilterByChatID(communityID.String()) + _, err = m.transport.RemoveFilterByChatID(communityID.String()) if err != nil { return nil, err } - if filter != nil { - response.RemovedFilters = append(response.RemovedFilters, filter) - } - response.AddCommunity(community) return response, nil } @@ -319,7 +308,7 @@ func (m *Messenger) CreateCommunityChat(communityID types.HexBytes, c *protobuf. if err != nil { return nil, err } - response.Filters = filters + m.scheduleSyncFilters(filters) return &response, m.saveChats(chats) } @@ -335,15 +324,12 @@ func (m *Messenger) CreateCommunity(request *requests.CreateCommunity) (*Messeng } // Init the community filter so we can receive messages on the community - filters, err := m.transport.InitCommunityFilters([]*ecdsa.PrivateKey{community.PrivateKey()}) + _, err = m.transport.InitCommunityFilters([]*ecdsa.PrivateKey{community.PrivateKey()}) if err != nil { return nil, err } - response := &MessengerResponse{ - Filters: filters, - } - + response := &MessengerResponse{} response.AddCommunity(community) return response, nil @@ -370,24 +356,28 @@ func (m *Messenger) ExportCommunity(id types.HexBytes) (*ecdsa.PrivateKey, error } func (m *Messenger) ImportCommunity(key *ecdsa.PrivateKey) (*MessengerResponse, error) { - org, err := m.communitiesManager.ImportCommunity(key) + community, err := m.communitiesManager.ImportCommunity(key) if err != nil { return nil, err } // Load filters - filters, err := m.transport.InitPublicFilters([]string{org.IDString()}) + _, err = m.transport.InitPublicFilters([]string{community.IDString()}) if err != nil { return nil, err } //request info already stored on mailserver, but its success is not crucial // for import - _ = m.RequestCommunityInfoFromMailserver(org.IDString()) + _ = m.RequestCommunityInfoFromMailserver(community.IDString()) - return &MessengerResponse{ - Filters: filters, - }, nil + // We add ourselves + _, err = m.communitiesManager.InviteUsersToCommunity(community.ID(), []*ecdsa.PublicKey{&m.identity.PublicKey}) + if err != nil { + return nil, err + } + + return m.JoinCommunity(community.ID()) } func (m *Messenger) InviteUsersToCommunity(request *requests.InviteUsersToCommunity) (*MessengerResponse, error) { diff --git a/protocol/messenger_config.go b/protocol/messenger_config.go index b80146e26..25a8026a2 100644 --- a/protocol/messenger_config.go +++ b/protocol/messenger_config.go @@ -20,13 +20,13 @@ type MessageDeliveredHandler func(string, string) type MessengerSignalsHandler interface { MessageDelivered(chatID string, messageID string) CommunityInfoFound(community *communities.Community) + MessengerResponse(response *MessengerResponse) } type config struct { // This needs to be exposed until we move here mailserver logic // as otherwise the client is not notified of a new filter and // won't be pulling messages from mailservers until it reloads the chats/filters - onNegotiatedFilters func([]*transport.Filter) onContactENSVerified func(*MessengerResponse) // systemMessagesTranslations holds translations for system-messages @@ -67,13 +67,6 @@ func WithSystemMessagesTranslations(t map[protobuf.MembershipUpdateEvent_EventTy } } -func WithOnNegotiatedFilters(h func([]*transport.Filter)) Option { - return func(c *config) error { - c.onNegotiatedFilters = h - return nil - } -} - func WithCustomLogger(logger *zap.Logger) Option { return func(c *config) error { c.logger = logger diff --git a/protocol/messenger_contacts.go b/protocol/messenger_contacts.go index 64b2b09a6..e7ee9baed 100644 --- a/protocol/messenger_contacts.go +++ b/protocol/messenger_contacts.go @@ -48,15 +48,10 @@ func (m *Messenger) AddContact(ctx context.Context, pubKey string) (*MessengerRe return nil, err } - // Create the corresponding profile chat - profileChatID := buildProfileChatID(contact.ID) - profileChat, ok := m.allChats.Load(profileChatID) + // Create the corresponding chat + profileChat := m.buildProfileChat(contact.ID) - if !ok { - profileChat = CreateProfileChat(profileChatID, contact.ID, m.getTimesource()) - } - - filters, err := m.Join(profileChat) + _, err = m.Join(profileChat) if err != nil { return nil, err } @@ -68,7 +63,6 @@ func (m *Messenger) AddContact(ctx context.Context, pubKey string) (*MessengerRe return nil, err } - response.Filters = filters response.AddChat(profileChat) publicKey, err := contact.PublicKey() @@ -176,6 +170,17 @@ func (m *Messenger) saveContact(contact *Contact) error { contact.Alias = name if m.isNewContact(contact) || m.hasNicknameChanged(contact) { + if m.isNewContact(contact) { + publicKey, err := contact.PublicKey() + if err != nil { + return err + } + filter, err := m.transport.JoinPrivate(publicKey) + if err != nil { + return err + } + m.scheduleSyncFilter(filter) + } err := m.syncContact(context.Background(), contact) if err != nil { return err diff --git a/protocol/messenger_installations_test.go b/protocol/messenger_installations_test.go index 33d0f6289..c829759f6 100644 --- a/protocol/messenger_installations_test.go +++ b/protocol/messenger_installations_test.go @@ -100,7 +100,7 @@ func (s *MessengerInstallationSuite) TestReceiveInstallation() { contactKey, err := crypto.GenerateKey() s.Require().NoError(err) - contact, err := buildContactFromPublicKey(&contactKey.PublicKey) + contact, err := BuildContactFromPublicKey(&contactKey.PublicKey) s.Require().NoError(err) contact.SystemTags = append(contact.SystemTags, contactAdded) err = s.m.SaveContact(contact) @@ -142,7 +142,7 @@ func (s *MessengerInstallationSuite) TestSyncInstallation() { contactKey, err := crypto.GenerateKey() s.Require().NoError(err) - contact, err := buildContactFromPublicKey(&contactKey.PublicKey) + contact, err := BuildContactFromPublicKey(&contactKey.PublicKey) s.Require().NoError(err) contact.SystemTags = append(contact.SystemTags, contactAdded) contact.LocalNickname = "Test Nickname" diff --git a/protocol/messenger_mailserver.go b/protocol/messenger_mailserver.go new file mode 100644 index 000000000..64c6ee03b --- /dev/null +++ b/protocol/messenger_mailserver.go @@ -0,0 +1,441 @@ +package protocol + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + "go.uber.org/zap" + + "github.com/status-im/status-go/eth-node/crypto" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/protocol/common" + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/protocol/transport" + "github.com/status-im/status-go/services/mailservers" +) + +func (m *Messenger) connectedToMailserver() bool { + return m.online() && m.mailserver != nil +} + +func (m *Messenger) scheduleSyncChat(chat *Chat) { + useMailservers, err := m.settings.GetUseMailservers() + if err != nil { + m.logger.Error("failed to get use mailservers", zap.Error(err)) + return + } + + if !useMailservers || !m.connectedToMailserver() { + return + } + + go func() { + response, err := m.syncChat(chat.ID) + + if err != nil { + m.logger.Error("failed to sync chat", zap.Error(err)) + return + } + + if m.config.messengerSignalsHandler != nil { + m.config.messengerSignalsHandler.MessengerResponse(response) + } + + }() +} + +func (m *Messenger) scheduleSyncFilter(filter *transport.Filter) { + m.scheduleSyncFilters([]*transport.Filter{filter}) + +} +func (m *Messenger) scheduleSyncFilters(filters []*transport.Filter) { + useMailservers, err := m.settings.GetUseMailservers() + if err != nil { + m.logger.Error("failed to get use mailservers", zap.Error(err)) + return + } + + if !useMailservers || !m.connectedToMailserver() { + return + } + + go func() { + response, err := m.syncFilters(filters) + + if err != nil { + m.logger.Error("failed to sync filter", zap.Error(err)) + return + } + + if m.config.messengerSignalsHandler != nil { + m.config.messengerSignalsHandler.MessengerResponse(response) + } + + }() +} + +func (m *Messenger) calculateMailserverTo() uint32 { + return uint32(m.getTimesource().GetCurrentTime() / 1000) +} + +func (m *Messenger) filtersForChat(chatID string) ([]*transport.Filter, error) { + chat, ok := m.allChats.Load(chatID) + if !ok { + return nil, ErrChatNotFound + } + var filters []*transport.Filter + + if chat.OneToOne() { + // We sync our own topic and any eventual negotiated + publicKeys := []string{common.PubkeyToHex(&m.identity.PublicKey), chatID} + + filters = m.transport.FiltersByIdentities(publicKeys) + + } else if chat.PrivateGroupChat() { + var publicKeys []string + for _, m := range chat.Members { + publicKeys = append(publicKeys, m.ID) + } + + filters = m.transport.FiltersByIdentities(publicKeys) + + } else { + filter := m.transport.FilterByChatID(chatID) + if filter == nil { + return nil, errors.New("no filter registered for given chat") + } + filters = []*transport.Filter{filter} + } + + return filters, nil +} + +func (m *Messenger) topicsForChat(chatID string) ([]types.TopicType, error) { + filters, err := m.filtersForChat(chatID) + if err != nil { + return nil, err + } + + var topics []types.TopicType + + for _, filter := range filters { + topics = append(topics, filter.Topic) + } + + return topics, nil +} + +// Assume is a public chat for now +func (m *Messenger) syncChat(chatID string) (*MessengerResponse, error) { + filters, err := m.filtersForChat(chatID) + if err != nil { + return nil, err + } + return m.syncFilters(filters) +} + +func (m *Messenger) defaultSyncInterval() uint32 { + return 60 * 60 * 24 +} + +func (m *Messenger) defaultSyncPeriod() uint32 { + return uint32(m.getTimesource().GetCurrentTime()/1000) - m.defaultSyncInterval() +} + +// capSyncPeriod caps the sync period to the default +func (m *Messenger) capSyncPeriod(period uint32) uint32 { + d := uint32(m.defaultSyncPeriod()) + if d > period { + return d + } + return period +} + +// RequestAllHistoricMessages requests all the historic messages for any topic +func (m *Messenger) RequestAllHistoricMessages() (*MessengerResponse, error) { + useMailservers, err := m.settings.GetUseMailservers() + if err != nil { + return nil, err + } + + if !useMailservers || !m.connectedToMailserver() { + return nil, nil + } + + return m.syncFilters(m.transport.Filters()) +} + +func (m *Messenger) syncFilters(filters []*transport.Filter) (*MessengerResponse, error) { + response := &MessengerResponse{} + topicInfo, err := m.mailserversDatabase.Topics() + if err != nil { + return nil, err + } + + topicsData := make(map[string]mailservers.MailserverTopic) + for _, topic := range topicInfo { + topicsData[topic.Topic] = topic + } + + batches := make(map[int]MailserverBatch) + + var syncedChatIDs []string + + to := m.calculateMailserverTo() + var syncedTopics []mailservers.MailserverTopic + for _, filter := range filters { + if !filter.Listen || filter.Ephemeral { + continue + } + + var chatID string + // If the filter has an identity, we use it as a chatID, otherwise is a public chat/community chat filter + if len(filter.Identity) != 0 { + chatID = filter.Identity + } else { + chatID = filter.ChatID + } + + syncedChatIDs = append(syncedChatIDs, chatID) + + topicData, ok := topicsData[filter.Topic.String()] + if !ok { + topicData = mailservers.MailserverTopic{ + Topic: filter.Topic.String(), + LastRequest: int(m.defaultSyncPeriod()), + } + } + batch, ok := batches[topicData.LastRequest] + if !ok { + from := m.capSyncPeriod(uint32(topicData.LastRequest)) + batch = MailserverBatch{From: from, To: to} + } + + batch.ChatIDs = append(batch.ChatIDs, chatID) + batch.Topics = append(batch.Topics, filter.Topic) + batches[topicData.LastRequest] = batch + // Set last request to the new `to` + topicData.LastRequest = int(to) + syncedTopics = append(syncedTopics, topicData) + } + + m.logger.Info("syncing topics", zap.Any("batches", batches)) + for _, batch := range batches { + err := m.processMailserverBatch(batch) + if err != nil { + return nil, err + } + } + + err = m.mailserversDatabase.AddTopics(syncedTopics) + if err != nil { + return nil, err + } + + var messagesToBeSaved []*common.Message + for _, batch := range batches { + for _, id := range batch.ChatIDs { + chat, ok := m.allChats.Load(id) + if !ok || !chat.Active || chat.Timeline() || chat.ProfileUpdates() { + continue + } + gap, err := m.calculateGapForChat(chat, batch.From) + if err != nil { + return nil, err + } + if chat.SyncedFrom == 0 || chat.SyncedFrom > batch.From { + chat.SyncedFrom = batch.From + } + + chat.SyncedTo = to + + err = m.persistence.SetSyncTimestamps(chat.SyncedFrom, chat.SyncedTo, chat.ID) + if err != nil { + return nil, err + } + + response.AddChat(chat) + if gap != nil { + response.AddMessage(gap) + messagesToBeSaved = append(messagesToBeSaved, gap) + } + // Calculate gaps + // If last-synced is 0, no gaps + // If last-synced < from, create gap from + } + } + + if len(messagesToBeSaved) > 0 { + err := m.persistence.SaveMessages(messagesToBeSaved) + if err != nil { + return nil, err + } + } + return response, nil +} + +func (m *Messenger) calculateGapForChat(chat *Chat, from uint32) (*common.Message, error) { + // Chat was never synced, no gap necessary + if chat.SyncedTo == 0 { + return nil, nil + } + + // If we filled the gap, nothing to do + if chat.SyncedTo >= from { + return nil, nil + } + + timestamp := m.getTimesource().GetCurrentTime() + + message := &common.Message{ + ChatMessage: protobuf.ChatMessage{ + ChatId: chat.ID, + Text: "Gap message", + MessageType: protobuf.MessageType_SYSTEM_MESSAGE_GAP, + ContentType: protobuf.ChatMessage_SYSTEM_MESSAGE_GAP, + Clock: uint64(from) * 1000, + Timestamp: timestamp, + }, + GapParameters: &common.GapParameters{ + From: chat.SyncedTo, + To: from, + }, + From: common.PubkeyToHex(&m.identity.PublicKey), + WhisperTimestamp: timestamp, + LocalChatID: chat.ID, + Seen: true, + ID: types.EncodeHex(crypto.Keccak256([]byte(fmt.Sprintf("%s-%d-%d", chat.ID, chat.SyncedTo, from)))), + } + + return message, m.persistence.SaveMessages([]*common.Message{message}) +} + +func (m *Messenger) processMailserverBatch(batch MailserverBatch) error { + m.logger.Info("syncing topic", zap.Any("topic", batch.Topics), zap.Int64("from", int64(batch.From)), zap.Int64("to", int64(batch.To))) + cursor, err := m.transport.SendMessagesRequestForTopics(context.Background(), m.mailserver, batch.From, batch.To, nil, batch.Topics, true) + if err != nil { + return err + } + for len(cursor) != 0 { + m.logger.Info("retrieved cursor", zap.Any("cursor", cursor)) + + cursor, err = m.transport.SendMessagesRequest(context.Background(), m.mailserver, batch.From, batch.To, cursor, true) + if err != nil { + return err + } + } + m.logger.Info("synced topic", zap.Any("topic", batch.Topics), zap.Int64("from", int64(batch.From)), zap.Int64("to", int64(batch.To))) + return nil +} + +type MailserverBatch struct { + From uint32 + To uint32 + Cursor string + Topics []types.TopicType + ChatIDs []string +} + +func (m *Messenger) RequestHistoricMessagesForFilter( + ctx context.Context, + from, to uint32, + cursor []byte, + filter *transport.Filter, + waitForResponse bool, +) ([]byte, error) { + if m.mailserver == nil { + return nil, errors.New("no mailserver selected") + } + + return m.transport.SendMessagesRequestForFilter(ctx, m.mailserver, from, to, cursor, filter, waitForResponse) +} + +func (m *Messenger) SyncChatFromSyncedFrom(chatID string) (uint32, error) { + topics, err := m.topicsForChat(chatID) + if err != nil { + return 0, nil + } + chat, ok := m.allChats.Load(chatID) + if !ok { + return 0, ErrChatNotFound + } + + batch := MailserverBatch{ + ChatIDs: []string{chatID}, + To: chat.SyncedFrom, + From: chat.SyncedFrom - m.defaultSyncInterval(), + Topics: topics, + } + + err = m.processMailserverBatch(batch) + if err != nil { + return 0, err + } + + if chat.SyncedFrom == 0 || chat.SyncedFrom > batch.From { + chat.SyncedFrom = batch.From + } + + err = m.persistence.SetSyncTimestamps(batch.From, chat.SyncedTo, chat.ID) + if err != nil { + return 0, err + } + + return batch.From, nil +} + +func (m *Messenger) FillGaps(chatID string, messageIDs []string) error { + messages, err := m.persistence.MessagesByIDs(messageIDs) + if err != nil { + return err + } + + _, ok := m.allChats.Load(chatID) + if !ok { + return errors.New("chat not existing") + } + + topics, err := m.topicsForChat(chatID) + if err != nil { + return err + } + + var lowestFrom, highestTo uint32 + + for _, message := range messages { + if message.GapParameters == nil { + return errors.New("can't sync non-gap message") + } + + if lowestFrom == 0 || lowestFrom > message.GapParameters.From { + lowestFrom = message.GapParameters.From + } + + if highestTo < message.GapParameters.To { + highestTo = message.GapParameters.To + } + } + + batch := MailserverBatch{ + ChatIDs: []string{chatID}, + To: highestTo, + From: lowestFrom, + Topics: topics, + } + + err = m.processMailserverBatch(batch) + if err != nil { + return err + } + + return m.persistence.DeleteMessages(messageIDs) +} + +func (m *Messenger) LoadFilters(filters []*transport.Filter) ([]*transport.Filter, error) { + return m.transport.LoadFilters(filters) +} + +func (m *Messenger) RemoveFilters(filters []*transport.Filter) error { + return m.transport.RemoveFilters(filters) +} diff --git a/protocol/messenger_response.go b/protocol/messenger_response.go index 41ac0fc11..6ddf7060b 100644 --- a/protocol/messenger_response.go +++ b/protocol/messenger_response.go @@ -6,7 +6,6 @@ import ( "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/communities" "github.com/status-im/status-go/protocol/encryption/multidevice" - "github.com/status-im/status-go/protocol/transport" localnotifications "github.com/status-im/status-go/services/local-notifications" "github.com/status-im/status-go/services/mailservers" ) @@ -19,11 +18,7 @@ type MessengerResponse struct { Invitations []*GroupChatInvitation CommunityChanges []*communities.CommunityChanges RequestsToJoinCommunity []*communities.RequestToJoin - Filters []*transport.Filter - RemovedFilters []*transport.Filter Mailservers []mailservers.Mailserver - MailserverTopics []mailservers.MailserverTopic - MailserverRanges []mailservers.ChatRequestRange // notifications a list of notifications derived from messenger events // that are useful to notify the user about @@ -40,18 +35,14 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) { Chats []*Chat `json:"chats,omitempty"` RemovedChats []string `json:"removedChats,omitempty"` Messages []*common.Message `json:"messages,omitempty"` - PinMessages []*common.PinMessage `json:"pinMessages,omitempty"` Contacts []*Contact `json:"contacts,omitempty"` Installations []*multidevice.Installation `json:"installations,omitempty"` + PinMessages []*common.PinMessage `json:"pinMessages,omitempty"` EmojiReactions []*EmojiReaction `json:"emojiReactions,omitempty"` Invitations []*GroupChatInvitation `json:"invitations,omitempty"` CommunityChanges []*communities.CommunityChanges `json:"communityChanges,omitempty"` RequestsToJoinCommunity []*communities.RequestToJoin `json:"requestsToJoinCommunity,omitempty"` - Filters []*transport.Filter `json:"filters,omitempty"` - RemovedFilters []*transport.Filter `json:"removedFilters,omitempty"` Mailservers []mailservers.Mailserver `json:"mailservers,omitempty"` - MailserverTopics []mailservers.MailserverTopic `json:"mailserverTopics,omitempty"` - MailserverRanges []mailservers.ChatRequestRange `json:"mailserverRanges,omitempty"` // Notifications a list of notifications derived from messenger events // that are useful to notify the user about Notifications []*localnotifications.Notification `json:"notifications"` @@ -65,11 +56,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) { Invitations: r.Invitations, CommunityChanges: r.CommunityChanges, RequestsToJoinCommunity: r.RequestsToJoinCommunity, - Filters: r.Filters, - RemovedFilters: r.RemovedFilters, Mailservers: r.Mailservers, - MailserverTopics: r.MailserverTopics, - MailserverRanges: r.MailserverRanges, } responseItem.Notifications = r.Notifications() @@ -132,12 +119,8 @@ func (r *MessengerResponse) IsEmpty() bool { len(r.EmojiReactions)+ len(r.communities)+ len(r.CommunityChanges)+ - len(r.Filters)+ - len(r.RemovedFilters)+ len(r.removedChats)+ - len(r.MailserverTopics)+ len(r.Mailservers)+ - len(r.MailserverRanges)+ len(r.notifications)+ len(r.activityCenterNotifications)+ len(r.RequestsToJoinCommunity) == 0 @@ -152,8 +135,6 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error { len(response.Invitations)+ len(response.RequestsToJoinCommunity)+ len(response.Mailservers)+ - len(response.MailserverTopics)+ - len(response.MailserverRanges)+ len(response.EmojiReactions)+ len(response.CommunityChanges) != 0 { return ErrNotImplemented @@ -163,8 +144,6 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error { r.AddRemovedChats(response.RemovedChats()) r.AddNotifications(response.Notifications()) r.overrideMessages(response.Messages) - r.overrideFilters(response.Filters) - r.overrideRemovedFilters(response.Filters) r.AddCommunities(response.Communities()) r.AddPinMessages(response.PinMessages()) @@ -187,38 +166,6 @@ func (r *MessengerResponse) overrideMessages(messages []*common.Message) { } } -// overrideFilters append new filters and override existing ones in response.Filters -func (r *MessengerResponse) overrideFilters(filters []*transport.Filter) { - for _, overrideFilter := range filters { - var found = false - for idx, filter := range r.Filters { - if filter.FilterID == overrideFilter.FilterID { - r.Filters[idx] = overrideFilter - found = true - } - } - if !found { - r.Filters = append(r.Filters, overrideFilter) - } - } -} - -// overrideRemovedFilters append removed filters and override existing ones in response.Filters -func (r *MessengerResponse) overrideRemovedFilters(filters []*transport.Filter) { - for _, overrideFilter := range filters { - var found = false - for idx, filter := range r.RemovedFilters { - if filter.FilterID == overrideFilter.FilterID { - r.RemovedFilters[idx] = overrideFilter - found = true - } - } - if !found { - r.RemovedFilters = append(r.RemovedFilters, overrideFilter) - } - } -} - func (r *MessengerResponse) AddCommunities(communities []*communities.Community) { for _, overrideCommunity := range communities { r.AddCommunity(overrideCommunity) @@ -314,3 +261,7 @@ func (r *MessengerResponse) AddPinMessages(pms []*common.PinMessage) { r.AddPinMessage(pm) } } + +func (r *MessengerResponse) AddMessage(message *common.Message) { + r.Messages = append(r.Messages, message) +} diff --git a/protocol/messenger_test.go b/protocol/messenger_test.go index a554a79b1..98f79d6eb 100644 --- a/protocol/messenger_test.go +++ b/protocol/messenger_test.go @@ -410,7 +410,7 @@ func (s *MessengerSuite) TestSendPublic() { } func (s *MessengerSuite) TestSendProfile() { - chat := CreateProfileChat("test-chat-profile", "0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), s.m.transport) + chat := CreateProfileChat("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), s.m.transport) chat.LastClockValue = uint64(100000000000000) err := s.m.SaveChat(chat) s.NoError(err) diff --git a/protocol/migrations/migrations.go b/protocol/migrations/migrations.go index 2782128ee..9bc712b68 100644 --- a/protocol/migrations/migrations.go +++ b/protocol/migrations/migrations.go @@ -29,6 +29,7 @@ // 1617694931_add_notification_center.up.sql (572B) // 1618923660_create_pin_messages.up.sql (265B) // 1619094007_add_joined_chat_field.up.sql (101B) +// 1619099821_add_last_synced_field.up.sql (226B) // README.md (554B) // doc.go (850B) @@ -114,7 +115,7 @@ func _000001_initDownDbSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1610007618, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5e, 0xbb, 0x3f, 0x1, 0x75, 0x19, 0x70, 0x86, 0xa7, 0x34, 0x40, 0x17, 0x34, 0x3e, 0x18, 0x51, 0x79, 0xd4, 0x22, 0xad, 0x8f, 0x80, 0xcc, 0xa6, 0xcc, 0x6, 0x2b, 0x62, 0x2, 0x47, 0xba, 0xf9}} return a, nil } @@ -134,7 +135,7 @@ func _000001_initUpDbSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2719, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2719, mode: os.FileMode(0644), modTime: time.Unix(1610007618, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x60, 0xdc, 0xeb, 0xe, 0xc2, 0x4f, 0x75, 0xa, 0xf6, 0x3e, 0xc7, 0xc4, 0x4, 0xe2, 0xe1, 0xa4, 0x73, 0x2f, 0x4a, 0xad, 0x1a, 0x0, 0xc3, 0x93, 0x9d, 0x77, 0x3e, 0x31, 0x91, 0x77, 0x2e, 0xc8}} return a, nil } @@ -154,7 +155,7 @@ func _000002_add_last_ens_clock_valueUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "000002_add_last_ens_clock_value.up.sql", size: 77, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "000002_add_last_ens_clock_value.up.sql", size: 77, mode: os.FileMode(0644), modTime: time.Unix(1610007618, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4d, 0x3, 0x8f, 0xd5, 0x85, 0x83, 0x47, 0xbe, 0xf9, 0x82, 0x7e, 0x81, 0xa4, 0xbd, 0xaa, 0xd5, 0x98, 0x18, 0x5, 0x2d, 0x82, 0x42, 0x3b, 0x3, 0x50, 0xc3, 0x1e, 0x84, 0x35, 0xf, 0xb6, 0x2b}} return a, nil } @@ -174,7 +175,7 @@ func _1586358095_add_replaceUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1586358095_add_replace.up.sql", size: 224, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "1586358095_add_replace.up.sql", size: 224, mode: os.FileMode(0644), modTime: time.Unix(1611588719, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0xb3, 0xa9, 0xc7, 0x7f, 0x9d, 0x8f, 0x43, 0x8c, 0x9e, 0x58, 0x8d, 0x44, 0xbc, 0xfa, 0x6b, 0x5f, 0x3f, 0x5a, 0xbe, 0xe8, 0xb1, 0x16, 0xf, 0x91, 0x2a, 0xa0, 0x71, 0xbb, 0x8d, 0x6b, 0xcb}} return a, nil } @@ -194,7 +195,7 @@ func _1588665364_add_image_dataUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1588665364_add_image_data.up.sql", size: 186, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1588665364_add_image_data.up.sql", size: 186, mode: os.FileMode(0644), modTime: time.Unix(1611588719, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd6, 0xc6, 0x35, 0xb4, 0x4c, 0x39, 0x96, 0x29, 0x30, 0xda, 0xf4, 0x8f, 0xcb, 0xf1, 0x9f, 0x84, 0xdc, 0x88, 0xd4, 0xd5, 0xbc, 0xb6, 0x5b, 0x46, 0x78, 0x67, 0x76, 0x1a, 0x5, 0x36, 0xdc, 0xe5}} return a, nil } @@ -214,7 +215,7 @@ func _1589365189_add_pow_targetUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1589365189_add_pow_target.up.sql", size: 66, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1589365189_add_pow_target.up.sql", size: 66, mode: os.FileMode(0644), modTime: time.Unix(1611588719, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4e, 0x3a, 0xe2, 0x2e, 0x7d, 0xaf, 0xbb, 0xcc, 0x21, 0xa1, 0x7a, 0x41, 0x9a, 0xd0, 0xbb, 0xa9, 0xc8, 0x35, 0xf9, 0x32, 0x34, 0x46, 0x44, 0x9a, 0x86, 0x40, 0x7c, 0xb9, 0x23, 0xc7, 0x3, 0x3f}} return a, nil } @@ -234,7 +235,7 @@ func _1591277220_add_index_messagesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1591277220_add_index_messages.up.sql", size: 240, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1591277220_add_index_messages.up.sql", size: 240, mode: os.FileMode(0644), modTime: time.Unix(1614609069, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9c, 0xfe, 0xbe, 0xd5, 0xb8, 0x8f, 0xdd, 0xef, 0xbb, 0xa8, 0xad, 0x7f, 0xed, 0x5b, 0x5b, 0x2f, 0xe6, 0x82, 0x27, 0x78, 0x1f, 0xb9, 0x57, 0xdc, 0x8, 0xc2, 0xb2, 0xa9, 0x9a, 0x4, 0xe1, 0x7a}} return a, nil } @@ -254,7 +255,7 @@ func _1593087212_add_mute_chat_and_raw_message_fieldsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1593087212_add_mute_chat_and_raw_message_fields.up.sql", size: 215, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1593087212_add_mute_chat_and_raw_message_fields.up.sql", size: 215, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x73, 0x99, 0x61, 0xd1, 0xaa, 0xb4, 0xbf, 0xaf, 0xd7, 0x20, 0x17, 0x40, 0xf9, 0x2, 0xfb, 0xcc, 0x40, 0x2a, 0xd, 0x86, 0x36, 0x30, 0x88, 0x89, 0x25, 0x80, 0x42, 0xb0, 0x5b, 0xe9, 0x73, 0x78}} return a, nil } @@ -274,7 +275,7 @@ func _1595862781_add_audio_dataUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1595862781_add_audio_data.up.sql", size: 246, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1595862781_add_audio_data.up.sql", size: 246, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xae, 0xd2, 0xee, 0x55, 0xfb, 0x36, 0xa4, 0x92, 0x66, 0xe, 0x81, 0x62, 0x1e, 0x7a, 0x69, 0xa, 0xd5, 0x4b, 0xa5, 0x6a, 0x8d, 0x1d, 0xce, 0xf3, 0x3e, 0xc0, 0x5f, 0x9c, 0x66, 0x1b, 0xb4, 0xed}} return a, nil } @@ -294,7 +295,7 @@ func _1595865249_create_emoji_reactions_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1595865249_create_emoji_reactions_table.up.sql", size: 300, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1595865249_create_emoji_reactions_table.up.sql", size: 300, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xc5, 0x43, 0x5c, 0x3d, 0x53, 0x43, 0x2c, 0x1a, 0xa5, 0xb6, 0xbf, 0x7, 0x4, 0x5a, 0x3e, 0x40, 0x8b, 0xa4, 0x57, 0x12, 0x58, 0xbc, 0x42, 0xe2, 0xc3, 0xde, 0x76, 0x98, 0x80, 0xe2, 0xbe}} return a, nil } @@ -314,7 +315,7 @@ func _1596805115_create_group_chat_invitations_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1596805115_create_group_chat_invitations_table.up.sql", size: 231, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1596805115_create_group_chat_invitations_table.up.sql", size: 231, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6d, 0xb1, 0x14, 0x6d, 0x54, 0x28, 0x67, 0xc3, 0x23, 0x6a, 0xfc, 0x80, 0xdf, 0x9e, 0x4c, 0x35, 0x36, 0xf, 0xf8, 0xf3, 0x5f, 0xae, 0xad, 0xb, 0xc1, 0x51, 0x8e, 0x17, 0x7, 0xe5, 0x7f, 0x91}} return a, nil } @@ -334,7 +335,7 @@ func _1597322655_add_invitation_admin_chat_fieldUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1597322655_add_invitation_admin_chat_field.up.sql", size: 54, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1597322655_add_invitation_admin_chat_field.up.sql", size: 54, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x7a, 0xa0, 0xf2, 0xdb, 0x13, 0x91, 0x91, 0xa8, 0x34, 0x1a, 0xa1, 0x49, 0x68, 0xd5, 0xae, 0x2c, 0xd8, 0xd5, 0xea, 0x8f, 0x8c, 0xc7, 0x2, 0x4e, 0x58, 0x2c, 0x3a, 0x14, 0xd4, 0x4f, 0x2c}} return a, nil } @@ -354,7 +355,7 @@ func _1597757544_add_nicknameUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1597757544_add_nickname.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1597757544_add_nickname.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xa2, 0x64, 0x50, 0xc5, 0x4, 0xb9, 0x8b, 0xd1, 0x18, 0x9b, 0xc3, 0x91, 0x36, 0x2a, 0x1f, 0xc3, 0x6c, 0x2d, 0x92, 0xf8, 0x5e, 0xff, 0xb1, 0x59, 0x61, 0x2, 0x1c, 0xe1, 0x85, 0x90, 0xa4}} return a, nil } @@ -374,7 +375,7 @@ func _1598955122_add_mentionsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1598955122_add_mentions.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1598955122_add_mentions.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8d, 0x22, 0x17, 0x92, 0xd2, 0x11, 0x4e, 0x7, 0x93, 0x9a, 0x55, 0xfd, 0xb, 0x97, 0xc4, 0x63, 0x6a, 0x81, 0x97, 0xcd, 0xb2, 0xf8, 0x4b, 0x5f, 0x3c, 0xfa, 0x3a, 0x38, 0x53, 0x10, 0xed, 0x9d}} return a, nil } @@ -394,7 +395,7 @@ func _1599641390_add_emoji_reactions_indexUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.up.sql", size: 126, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.up.sql", size: 126, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf9, 0xd8, 0xdc, 0xa7, 0xb, 0x92, 0x7a, 0x61, 0x37, 0x24, 0x1c, 0x77, 0x5e, 0xe, 0x7e, 0xfc, 0x9f, 0x98, 0x7b, 0x65, 0xe7, 0xf9, 0x71, 0x57, 0x89, 0x2d, 0x90, 0x1b, 0xf6, 0x5e, 0x37, 0xe8}} return a, nil } @@ -414,7 +415,7 @@ func _1599720851_add_seen_index_remove_long_messagesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1599720851_add_seen_index_remove_long_messages.up.sql", size: 150, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1599720851_add_seen_index_remove_long_messages.up.sql", size: 150, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x24, 0x1c, 0xc4, 0x78, 0x91, 0xc7, 0xeb, 0xfe, 0xc8, 0xa0, 0xd8, 0x13, 0x27, 0x97, 0xc8, 0x96, 0x56, 0x97, 0x33, 0x2c, 0x1e, 0x16, 0x8a, 0xd3, 0x49, 0x99, 0x3, 0xe9, 0xbb, 0xc4, 0x5, 0x3c}} return a, nil } @@ -434,7 +435,7 @@ func _1603198582_add_profile_chat_fieldUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1603198582_add_profile_chat_field.up.sql", size: 45, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1603198582_add_profile_chat_field.up.sql", size: 45, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xaa, 0xca, 0xe, 0x46, 0xa0, 0x9, 0x9d, 0x47, 0x57, 0xe9, 0xfb, 0x17, 0xeb, 0x9c, 0xf6, 0xb8, 0x1d, 0xe9, 0xd, 0x0, 0xd5, 0xe5, 0xd8, 0x9e, 0x60, 0xa, 0xbf, 0x32, 0x2c, 0x52, 0x7f, 0x6a}} return a, nil } @@ -454,7 +455,7 @@ func _1603816533_add_linksUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1603816533_add_links.up.sql", size: 48, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1603816533_add_links.up.sql", size: 48, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0x24, 0xd6, 0x1d, 0xa, 0x83, 0x1e, 0x4d, 0xf, 0xae, 0x4d, 0x8c, 0x51, 0x32, 0xa8, 0x37, 0xb0, 0x14, 0xfb, 0x32, 0x34, 0xc8, 0xc, 0x4e, 0x5b, 0xc5, 0x15, 0x65, 0x73, 0x0, 0x0, 0x1d}} return a, nil } @@ -474,7 +475,7 @@ func _1603888149_create_chat_identity_last_published_tableUpSql() (*asset, error return nil, err } - info := bindataFileInfo{name: "1603888149_create_chat_identity_last_published_table.up.sql", size: 407, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1603888149_create_chat_identity_last_published_table.up.sql", size: 407, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7f, 0x9, 0xf, 0xfb, 0xdb, 0x3c, 0x86, 0x70, 0x82, 0xda, 0x10, 0x25, 0xe2, 0x4e, 0x40, 0x45, 0xab, 0x8b, 0x1c, 0x91, 0x7c, 0xf1, 0x70, 0x2e, 0x81, 0xf3, 0x71, 0x45, 0xda, 0xe2, 0xa4, 0x57}} return a, nil } @@ -494,7 +495,7 @@ func _1605075346_add_communitiesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1605075346_add_communities.up.sql", size: 6971, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1605075346_add_communities.up.sql", size: 6971, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1f, 0x64, 0xea, 0xb4, 0xae, 0x9e, 0xdb, 0x9, 0x58, 0xb6, 0x5c, 0x7a, 0x50, 0xc5, 0xfe, 0x93, 0x5d, 0x36, 0x85, 0x5d, 0x6a, 0xba, 0xc9, 0x7e, 0x84, 0xd7, 0xbf, 0x2a, 0x53, 0xf3, 0x97, 0xf1}} return a, nil } @@ -514,7 +515,7 @@ func _1610117927_add_message_cacheUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1610117927_add_message_cache.up.sql", size: 142, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1610117927_add_message_cache.up.sql", size: 142, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0xf1, 0xf0, 0x82, 0x79, 0x28, 0x19, 0xc2, 0x39, 0x6a, 0xa5, 0x96, 0x59, 0x23, 0xa0, 0xed, 0x60, 0x58, 0x86, 0x9, 0xb9, 0xad, 0xfb, 0xa, 0xe3, 0x47, 0x6e, 0xa1, 0x18, 0xe8, 0x39, 0x2c}} return a, nil } @@ -534,7 +535,7 @@ func _1610959908_add_dont_wrap_to_raw_messagesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1610959908_add_dont_wrap_to_raw_messages.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1610959908_add_dont_wrap_to_raw_messages.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x71, 0x2, 0x9a, 0xca, 0xd4, 0x38, 0x44, 0x30, 0x2b, 0xa8, 0x27, 0x32, 0x63, 0x53, 0x22, 0x60, 0x59, 0x84, 0x23, 0x96, 0x77, 0xf0, 0x56, 0xd7, 0x94, 0xe0, 0x95, 0x28, 0x6, 0x1d, 0x4e, 0xb1}} return a, nil } @@ -554,7 +555,7 @@ func _1610960912_add_send_on_personal_topicUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1610960912_add_send_on_personal_topic.up.sql", size: 82, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1610960912_add_send_on_personal_topic.up.sql", size: 82, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0xac, 0x2f, 0xc4, 0xd, 0xa7, 0x1b, 0x37, 0x30, 0xc2, 0x68, 0xee, 0xde, 0x54, 0x5e, 0xbf, 0x3f, 0xa0, 0xd6, 0xc6, 0x9f, 0xd4, 0x34, 0x12, 0x76, 0x1e, 0x66, 0x4a, 0xfc, 0xf, 0xee, 0xc9}} return a, nil } @@ -574,7 +575,7 @@ func _1612870480_add_datasync_idUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1612870480_add_datasync_id.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1612870480_add_datasync_id.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0x9a, 0xbc, 0xfa, 0xaa, 0x8c, 0x9c, 0x37, 0x67, 0x15, 0x9c, 0x7e, 0x78, 0x75, 0x66, 0x82, 0x18, 0x72, 0x10, 0xbc, 0xd4, 0xab, 0x44, 0xfe, 0x57, 0x85, 0x6d, 0x19, 0xf5, 0x96, 0x8a, 0xbe}} return a, nil } @@ -594,7 +595,7 @@ func _1614152139_add_communities_request_to_joinUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1614152139_add_communities_request_to_join.up.sql", size: 831, mode: os.FileMode(0644), modTime: time.Unix(1614686366, 0)} + info := bindataFileInfo{name: "1614152139_add_communities_request_to_join.up.sql", size: 831, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x11, 0x3, 0x26, 0xf9, 0x29, 0x50, 0x4f, 0xcd, 0x46, 0xe5, 0xb1, 0x6b, 0xb9, 0x2, 0x40, 0xb1, 0xdf, 0x4a, 0x4c, 0x7a, 0xda, 0x3, 0x35, 0xcd, 0x2d, 0xcc, 0x80, 0x7d, 0x57, 0x5f, 0x3, 0x5c}} return a, nil } @@ -614,7 +615,7 @@ func _1615374373_add_confirmationsUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1615374373_add_confirmations.up.sql", size: 227, mode: os.FileMode(0644), modTime: time.Unix(1616402204, 0)} + info := bindataFileInfo{name: "1615374373_add_confirmations.up.sql", size: 227, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdd, 0xa6, 0x65, 0xc5, 0x1d, 0xb2, 0x77, 0x36, 0xe3, 0x79, 0xda, 0xe8, 0x7a, 0xa4, 0xdf, 0x45, 0xae, 0xd8, 0xb4, 0xba, 0x90, 0xfd, 0x74, 0x71, 0x14, 0x75, 0x73, 0x72, 0xb9, 0x9e, 0x1, 0x81}} return a, nil } @@ -634,7 +635,7 @@ func _1617694931_add_notification_centerUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1617694931_add_notification_center.up.sql", size: 572, mode: os.FileMode(0644), modTime: time.Unix(1619093832, 0)} + info := bindataFileInfo{name: "1617694931_add_notification_center.up.sql", size: 572, mode: os.FileMode(0644), modTime: time.Unix(1618913882, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x10, 0x45, 0xc6, 0xc9, 0x73, 0xbb, 0x1f, 0xda, 0xa3, 0x4d, 0x19, 0x98, 0x85, 0x2d, 0xca, 0xda, 0xcc, 0x3b, 0x32, 0xff, 0xc7, 0x7b, 0xe3, 0x9f, 0x9b, 0x2a, 0x93, 0xf5, 0xdf, 0x65, 0x38, 0x91}} return a, nil } @@ -654,7 +655,7 @@ func _1618923660_create_pin_messagesUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1618923660_create_pin_messages.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1621327851, 0)} + info := bindataFileInfo{name: "1618923660_create_pin_messages.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1621335496, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x61, 0x44, 0x3a, 0xbe, 0x30, 0xd2, 0x7e, 0xc0, 0xe2, 0x8e, 0x65, 0x53, 0x54, 0xbb, 0x7a, 0x1c, 0xb3, 0x5d, 0xd2, 0xa6, 0xa9, 0x28, 0xb7, 0xa4, 0x5f, 0x8b, 0x9, 0x5f, 0x17, 0xc1, 0x85, 0x21}} return a, nil } @@ -674,11 +675,31 @@ func _1619094007_add_joined_chat_fieldUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1619094007_add_joined_chat_field.up.sql", size: 101, mode: os.FileMode(0644), modTime: time.Unix(1621327851, 0)} + info := bindataFileInfo{name: "1619094007_add_joined_chat_field.up.sql", size: 101, mode: os.FileMode(0644), modTime: time.Unix(1621335574, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfa, 0x30, 0x81, 0x3a, 0x2f, 0x9f, 0xb3, 0x0, 0x55, 0x8e, 0x1d, 0xa8, 0xb0, 0x68, 0xf0, 0x40, 0x1a, 0x6c, 0xaa, 0xfc, 0x33, 0xd1, 0xd1, 0x55, 0x3f, 0xf2, 0xbd, 0x54, 0xa1, 0x2b, 0x40, 0x95}} return a, nil } +var __1619099821_add_last_synced_fieldUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\xce\x48\x2c\x29\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x28\xae\xcc\x4b\x4e\x4d\x89\x2f\xc9\x57\xf0\xf4\x0b\x71\x75\x77\x0d\x52\x70\x71\x75\x73\x0c\xf5\x09\x51\x30\xb0\xe6\x22\x46\x67\x5a\x51\x7e\x2e\x21\xbd\xa5\xc5\xa9\x45\xf1\xb9\xa9\xc5\xc5\x89\xe9\xa9\x28\x66\xa4\x27\x16\xa0\x18\x40\x82\x36\x84\x8b\xad\xb9\x00\x01\x00\x00\xff\xff\x9d\x7c\x6a\xe7\xe2\x00\x00\x00") + +func _1619099821_add_last_synced_fieldUpSqlBytes() ([]byte, error) { + return bindataRead( + __1619099821_add_last_synced_fieldUpSql, + "1619099821_add_last_synced_field.up.sql", + ) +} + +func _1619099821_add_last_synced_fieldUpSql() (*asset, error) { + bytes, err := _1619099821_add_last_synced_fieldUpSqlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "1619099821_add_last_synced_field.up.sql", size: 226, mode: os.FileMode(0644), modTime: time.Unix(1621335717, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf, 0x52, 0x22, 0xe, 0x2f, 0xd7, 0x93, 0x5f, 0x42, 0xc2, 0x93, 0x4, 0x35, 0x6f, 0xc9, 0x19, 0xed, 0x6b, 0x52, 0x6f, 0xae, 0x99, 0xe2, 0x68, 0x3d, 0x4f, 0x40, 0xe, 0xe1, 0xa, 0x47, 0x21}} + return a, nil +} + var _readmeMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x91\xc1\xce\xd3\x30\x10\x84\xef\x7e\x8a\x91\x7a\x01\xa9\x2a\x8f\xc0\x0d\x71\x82\x03\x48\x1c\xc9\x36\x9e\x36\x96\x1c\x6f\xf0\xae\x93\xe6\xed\x91\xa3\xc2\xdf\xff\x66\xed\xd8\x33\xdf\x78\x4f\xa7\x13\xbe\xea\x06\x57\x6c\x35\x39\x31\xa7\x7b\x15\x4f\x5a\xec\x73\x08\xbf\x08\x2d\x79\x7f\x4a\x43\x5b\x86\x17\xfd\x8c\x21\xea\x56\x5e\x47\x90\x4a\x14\x75\x48\xde\x64\x37\x2c\x6a\x96\xae\x99\x48\x05\xf6\x27\x77\x13\xad\x08\xae\x8a\x51\xe7\x25\xf3\xf1\xa9\x9f\xf9\x58\x58\x2c\xad\xbc\xe0\x8b\x56\xf0\x21\x5d\xeb\x4c\x95\xb3\xae\x84\x60\xd4\xdc\xe6\x82\x5d\x1b\x36\x6d\x39\x62\x92\xf5\xb8\x11\xdb\x92\xd3\x28\xce\xe0\x13\xe1\x72\xcd\x3c\x63\xd4\x65\x87\xae\xac\xe8\xc3\x28\x2e\x67\x44\x66\x3a\x21\x25\xa2\x72\xac\x14\x67\xbc\x84\x9f\x53\x32\x8c\x52\x70\x25\x56\xd6\xfd\x8d\x05\x37\xad\x30\x9d\x9f\xa6\x86\x0f\xcd\x58\x7f\xcf\x34\x93\x3b\xed\x90\x9f\xa4\x1f\xcf\x30\x85\x4d\x07\x58\xaf\x7f\x25\xc4\x9d\xf3\x72\x64\x84\xd0\x7f\xf9\x9b\x3a\x2d\x84\xef\x85\x48\x66\x8d\xd8\x88\x9b\x8c\x8c\x98\x5b\xf6\x74\x14\x4e\x33\x0d\xc9\xe0\x93\x38\xda\x12\xc5\x69\xbd\xe4\xf0\x2e\x7a\x78\x07\x1c\xfe\x13\x9f\x91\x29\x31\x95\x7b\x7f\x62\x59\x37\xb4\xe5\x5e\x25\xfe\x33\xee\xd5\x53\x71\xd6\xda\x3a\xd8\xcb\xde\x2e\xf8\xa1\x90\x55\x53\x0c\xc7\xaa\x0d\xe9\x76\x14\x29\x1c\x7b\x68\xdd\x2f\xe1\x6f\x00\x00\x00\xff\xff\x3c\x0a\xc2\xfe\x2a\x02\x00\x00") func readmeMdBytes() ([]byte, error) { @@ -694,7 +715,7 @@ func readmeMd() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "README.md", size: 554, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "README.md", size: 554, mode: os.FileMode(0644), modTime: time.Unix(1617280156, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1c, 0x6e, 0xfb, 0xcc, 0x81, 0x94, 0x4d, 0x8c, 0xa0, 0x3b, 0x5, 0xb0, 0x18, 0xd6, 0xbb, 0xb3, 0x79, 0xc8, 0x8f, 0xff, 0xc1, 0x10, 0xf9, 0xf, 0x20, 0x1b, 0x4a, 0x74, 0x96, 0x42, 0xd7, 0xa8}} return a, nil } @@ -714,7 +735,7 @@ func docGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "doc.go", size: 850, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "doc.go", size: 850, mode: os.FileMode(0644), modTime: time.Unix(1611588719, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa0, 0xcc, 0x41, 0xe1, 0x61, 0x12, 0x97, 0xe, 0x36, 0x8c, 0xa7, 0x9e, 0xe0, 0x6e, 0x59, 0x9e, 0xee, 0xd5, 0x4a, 0xcf, 0x1e, 0x60, 0xd6, 0xc3, 0x3a, 0xc9, 0x6c, 0xf2, 0x86, 0x5a, 0xb4, 0x1e}} return a, nil } @@ -868,6 +889,8 @@ var _bindata = map[string]func() (*asset, error){ "1619094007_add_joined_chat_field.up.sql": _1619094007_add_joined_chat_fieldUpSql, + "1619099821_add_last_synced_field.up.sql": _1619099821_add_last_synced_fieldUpSql, + "README.md": readmeMd, "doc.go": docGo, @@ -943,6 +966,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "1617694931_add_notification_center.up.sql": &bintree{_1617694931_add_notification_centerUpSql, map[string]*bintree{}}, "1618923660_create_pin_messages.up.sql": &bintree{_1618923660_create_pin_messagesUpSql, map[string]*bintree{}}, "1619094007_add_joined_chat_field.up.sql": &bintree{_1619094007_add_joined_chat_fieldUpSql, map[string]*bintree{}}, + "1619099821_add_last_synced_field.up.sql": &bintree{_1619099821_add_last_synced_fieldUpSql, map[string]*bintree{}}, "README.md": &bintree{readmeMd, map[string]*bintree{}}, "doc.go": &bintree{docGo, map[string]*bintree{}}, }} diff --git a/protocol/migrations/sqlite/1619099821_add_last_synced_field.up.sql b/protocol/migrations/sqlite/1619099821_add_last_synced_field.up.sql new file mode 100644 index 000000000..7e53bc7cc --- /dev/null +++ b/protocol/migrations/sqlite/1619099821_add_last_synced_field.up.sql @@ -0,0 +1,4 @@ +ALTER TABLE chats ADD COLUMN synced_to INTEGER DEFAULT 0; +ALTER TABLE chats ADD COLUMN synced_from INTEGER DEFAULT 0; +ALTER TABLE user_messages ADD COLUMN gap_from INTEGER; +ALTER TABLE user_messages ADD COLUMN gap_to INTEGER; diff --git a/protocol/persistence.go b/protocol/persistence.go index 32d094203..201b41c4a 100644 --- a/protocol/persistence.go +++ b/protocol/persistence.go @@ -164,6 +164,11 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error { return err } +func (db sqlitePersistence) SetSyncTimestamps(syncedFrom, syncedTo uint32, chatID string) error { + _, err := db.db.Exec(`UPDATE chats SET synced_from = ?, synced_to = ? WHERE id = ?`, syncedFrom, syncedTo, chatID) + return err +} + func (db sqlitePersistence) DeleteChat(chatID string) (err error) { var tx *sql.Tx tx, err = db.db.BeginTx(context.Background(), &sql.TxOptions{}) @@ -236,7 +241,9 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) { chats.invitation_admin, chats.profile, chats.community_id, - chats.joined, + chats.joined, + chats.synced_from, + chats.synced_to, contacts.identicon, contacts.alias FROM chats LEFT JOIN contacts ON chats.id = contacts.id @@ -253,6 +260,8 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) { identicon sql.NullString invitationAdmin sql.NullString profile sql.NullString + syncedFrom sql.NullInt64 + syncedTo sql.NullInt64 chat Chat encodedMembers []byte encodedMembershipUpdates []byte @@ -276,6 +285,8 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) { &profile, &chat.CommunityID, &chat.Joined, + &syncedFrom, + &syncedTo, &identicon, &alias, ) @@ -306,6 +317,14 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) { return } + if syncedFrom.Valid { + chat.SyncedFrom = uint32(syncedFrom.Int64) + } + + if syncedTo.Valid { + chat.SyncedTo = uint32(syncedTo.Int64) + } + // Restore last message if lastMessageBytes != nil { message := &common.Message{} diff --git a/protocol/protobuf/chat_message.pb.go b/protocol/protobuf/chat_message.pb.go index 0cd371bc7..28fc44c03 100644 --- a/protocol/protobuf/chat_message.pb.go +++ b/protocol/protobuf/chat_message.pb.go @@ -62,19 +62,22 @@ const ( ChatMessage_IMAGE ChatMessage_ContentType = 7 ChatMessage_AUDIO ChatMessage_ContentType = 8 ChatMessage_COMMUNITY ChatMessage_ContentType = 9 + // Only local + ChatMessage_SYSTEM_MESSAGE_GAP ChatMessage_ContentType = 10 ) var ChatMessage_ContentType_name = map[int32]string{ - 0: "UNKNOWN_CONTENT_TYPE", - 1: "TEXT_PLAIN", - 2: "STICKER", - 3: "STATUS", - 4: "EMOJI", - 5: "TRANSACTION_COMMAND", - 6: "SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP", - 7: "IMAGE", - 8: "AUDIO", - 9: "COMMUNITY", + 0: "UNKNOWN_CONTENT_TYPE", + 1: "TEXT_PLAIN", + 2: "STICKER", + 3: "STATUS", + 4: "EMOJI", + 5: "TRANSACTION_COMMAND", + 6: "SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP", + 7: "IMAGE", + 8: "AUDIO", + 9: "COMMUNITY", + 10: "SYSTEM_MESSAGE_GAP", } var ChatMessage_ContentType_value = map[string]int32{ @@ -88,6 +91,7 @@ var ChatMessage_ContentType_value = map[string]int32{ "IMAGE": 7, "AUDIO": 8, "COMMUNITY": 9, + "SYSTEM_MESSAGE_GAP": 10, } func (x ChatMessage_ContentType) String() string { @@ -456,44 +460,45 @@ func init() { } var fileDescriptor_263952f55fd35689 = []byte{ - // 624 bytes of a gzipped FileDescriptorProto + // 631 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x53, 0xcd, 0x4e, 0xdb, 0x4c, 0x14, 0xc5, 0x60, 0xc7, 0xf1, 0x75, 0x40, 0xd6, 0xc0, 0x07, 0xf3, 0x55, 0x55, 0x9b, 0x46, 0x95, - 0x9a, 0x55, 0x16, 0x94, 0x4a, 0x6c, 0xdd, 0x60, 0x81, 0x4b, 0xed, 0xa4, 0xe3, 0x49, 0x5b, 0x56, - 0xd6, 0xe0, 0x4c, 0x89, 0x05, 0xfe, 0x51, 0x3c, 0x91, 0x9a, 0x17, 0xeb, 0x0b, 0x74, 0xd1, 0xd7, - 0xaa, 0x66, 0x8c, 0xe3, 0xc0, 0xa6, 0xab, 0xdc, 0x7b, 0xe7, 0x9c, 0xe3, 0x3b, 0x67, 0x4e, 0x00, - 0x25, 0x0b, 0x26, 0xe2, 0x8c, 0x57, 0x15, 0xbb, 0xe3, 0xa3, 0x72, 0x59, 0x88, 0x02, 0x75, 0xd5, - 0xcf, 0xed, 0xea, 0xc7, 0x0b, 0x9b, 0xe7, 0xab, 0xac, 0xaa, 0xc7, 0x83, 0x73, 0x38, 0x88, 0x44, - 0x9a, 0xdc, 0xf3, 0x65, 0x50, 0xc3, 0x11, 0x02, 0x7d, 0xc1, 0xaa, 0x05, 0xd6, 0xfa, 0xda, 0xd0, - 0x22, 0xaa, 0x96, 0xb3, 0x92, 0x25, 0xf7, 0x78, 0xb7, 0xaf, 0x0d, 0x0d, 0xa2, 0xea, 0xc1, 0x17, - 0xe8, 0xf9, 0x19, 0xbb, 0xe3, 0x0d, 0x0f, 0x83, 0x59, 0xb2, 0xf5, 0x43, 0xc1, 0xe6, 0x8a, 0xda, - 0x23, 0x4d, 0x8b, 0xde, 0x81, 0x2e, 0xd6, 0x25, 0x57, 0xec, 0x83, 0xd3, 0xc3, 0x51, 0xb3, 0xc9, - 0x48, 0xf1, 0xe9, 0xba, 0xe4, 0x44, 0x01, 0x06, 0xbf, 0x34, 0xe8, 0xb9, 0xab, 0x79, 0x5a, 0xfc, + 0x9a, 0x55, 0x16, 0x94, 0x4a, 0x6c, 0xdd, 0x60, 0x05, 0x97, 0xda, 0x49, 0xc7, 0x93, 0xb6, 0xac, + 0xac, 0xc1, 0x99, 0x12, 0x0b, 0xfc, 0xa3, 0x78, 0x22, 0x35, 0x2f, 0xd6, 0x97, 0xe9, 0xa2, 0xaf, + 0x52, 0xcd, 0x18, 0xe3, 0xc0, 0xa6, 0xab, 0xdc, 0x7b, 0xe7, 0x9c, 0xe3, 0x3b, 0x67, 0x4e, 0x00, + 0x25, 0x4b, 0x26, 0xe2, 0x8c, 0x57, 0x15, 0xbb, 0xe5, 0xa3, 0x72, 0x55, 0x88, 0x02, 0x75, 0xd5, + 0xcf, 0xcd, 0xfa, 0xc7, 0x0b, 0x9b, 0xe7, 0xeb, 0xac, 0xaa, 0xc7, 0x83, 0x73, 0x38, 0x88, 0x44, + 0x9a, 0xdc, 0xf1, 0x55, 0x50, 0xc3, 0x11, 0x02, 0x7d, 0xc9, 0xaa, 0x25, 0xd6, 0xfa, 0xda, 0xd0, + 0x22, 0xaa, 0x96, 0xb3, 0x92, 0x25, 0x77, 0x78, 0xb7, 0xaf, 0x0d, 0x0d, 0xa2, 0xea, 0xc1, 0x17, + 0xe8, 0xf9, 0x19, 0xbb, 0xe5, 0x0d, 0x0f, 0x83, 0x59, 0xb2, 0xcd, 0x7d, 0xc1, 0x16, 0x8a, 0xda, + 0x23, 0x4d, 0x8b, 0xde, 0x81, 0x2e, 0x36, 0x25, 0x57, 0xec, 0x83, 0xd3, 0xc3, 0x51, 0xb3, 0xc9, + 0x48, 0xf1, 0xe9, 0xa6, 0xe4, 0x44, 0x01, 0x06, 0xbf, 0x34, 0xe8, 0xb9, 0xeb, 0x45, 0x5a, 0xfc, 0x5b, 0xf3, 0xec, 0x89, 0x66, 0xbf, 0xd5, 0xdc, 0xe6, 0xd7, 0x4d, 0xfb, 0x01, 0xf4, 0x1a, 0xec, - 0xf9, 0x6a, 0xc9, 0x44, 0x5a, 0xe4, 0x71, 0x56, 0xe1, 0xbd, 0xbe, 0x36, 0xd4, 0x09, 0x34, 0xa3, - 0xa0, 0x1a, 0x7c, 0x00, 0x6b, 0xc3, 0x41, 0xc7, 0x80, 0x66, 0xe1, 0x75, 0x38, 0xf9, 0x16, 0xc6, - 0xee, 0xec, 0xc2, 0x9f, 0xc4, 0xf4, 0x66, 0xea, 0x39, 0x3b, 0xc8, 0x84, 0x3d, 0xd7, 0x1d, 0x3b, - 0x9a, 0x2a, 0x02, 0xe2, 0xec, 0x0e, 0xfe, 0x18, 0x60, 0x8f, 0x17, 0x4c, 0x34, 0x7b, 0x1f, 0x81, - 0x91, 0x3c, 0x14, 0xc9, 0xbd, 0xda, 0x5a, 0x27, 0x75, 0x83, 0x5e, 0x82, 0x25, 0xd2, 0x8c, 0x57, - 0x82, 0x65, 0xa5, 0x5a, 0x5c, 0x27, 0xed, 0x40, 0x7a, 0x2c, 0xf8, 0x4f, 0xa1, 0x96, 0xb2, 0x88, - 0xaa, 0xe5, 0xbe, 0x4b, 0x5e, 0x95, 0x45, 0x5e, 0xf1, 0x58, 0x14, 0x58, 0x57, 0x47, 0xd0, 0x8c, - 0x68, 0x81, 0xfe, 0x87, 0x2e, 0xcf, 0xab, 0x38, 0x67, 0x19, 0xc7, 0x86, 0x3a, 0x35, 0x79, 0x5e, - 0x85, 0x2c, 0xe3, 0xe8, 0x04, 0x4c, 0x15, 0x83, 0x74, 0x8e, 0x3b, 0xea, 0xa4, 0x23, 0x5b, 0x7f, - 0x8e, 0xce, 0xa1, 0xf7, 0x18, 0x8d, 0x58, 0x59, 0x68, 0x2a, 0x0b, 0xff, 0x6b, 0x2d, 0x7c, 0xbc, - 0x85, 0xf2, 0xcd, 0xce, 0xda, 0x06, 0x5d, 0x40, 0x2f, 0x29, 0x72, 0xc1, 0x73, 0x51, 0x33, 0xbb, - 0x8a, 0xf9, 0xa6, 0x65, 0x6e, 0x79, 0x30, 0x1a, 0xd7, 0xc8, 0x5a, 0x25, 0x69, 0x1b, 0x74, 0x06, - 0x66, 0x55, 0x47, 0x0e, 0x5b, 0x7d, 0x6d, 0x68, 0x9f, 0xe2, 0x56, 0xe0, 0x69, 0x16, 0xaf, 0x76, - 0x48, 0x03, 0x45, 0x23, 0x30, 0x52, 0x19, 0x17, 0x0c, 0x8a, 0x73, 0xfc, 0x2c, 0x45, 0x2d, 0xa3, - 0x86, 0x49, 0x3c, 0x93, 0x2f, 0x89, 0xed, 0xe7, 0xf8, 0xed, 0x84, 0x48, 0xbc, 0x82, 0xa1, 0x57, - 0x60, 0x25, 0x45, 0x96, 0xad, 0xf2, 0x54, 0xac, 0x71, 0x4f, 0x86, 0xed, 0x6a, 0x87, 0xb4, 0x23, - 0xf9, 0xa4, 0x77, 0x4b, 0x96, 0x0b, 0xbc, 0xaf, 0x82, 0x58, 0x37, 0x83, 0xdf, 0x1a, 0xd8, 0x5b, - 0x17, 0x45, 0x18, 0x8e, 0x9a, 0xc8, 0x8c, 0x27, 0x21, 0xf5, 0x42, 0xda, 0x84, 0xe6, 0x00, 0x80, - 0x7a, 0xdf, 0x69, 0x3c, 0xfd, 0xec, 0xfa, 0xa1, 0xa3, 0x21, 0x1b, 0xcc, 0x88, 0xfa, 0xe3, 0x6b, - 0x8f, 0x38, 0xbb, 0x08, 0xa0, 0x13, 0x51, 0x97, 0xce, 0x22, 0x67, 0x0f, 0x59, 0x60, 0x78, 0xc1, - 0xe4, 0x93, 0xef, 0xe8, 0xe8, 0x04, 0x0e, 0x29, 0x71, 0xc3, 0xc8, 0x1d, 0x53, 0x7f, 0x22, 0x15, - 0x83, 0xc0, 0x0d, 0x2f, 0x1c, 0x03, 0x0d, 0xe1, 0x6d, 0x74, 0x13, 0x51, 0x2f, 0x88, 0x03, 0x2f, - 0x8a, 0xdc, 0x4b, 0x6f, 0xf3, 0xb5, 0x29, 0xf1, 0xbf, 0xba, 0xd4, 0x8b, 0x2f, 0xc9, 0x64, 0x36, - 0x75, 0x3a, 0x52, 0xcd, 0x0f, 0xdc, 0x4b, 0xcf, 0x31, 0x65, 0xa9, 0x62, 0xec, 0x74, 0xd1, 0x3e, - 0x58, 0x52, 0x6c, 0x16, 0xfa, 0xf4, 0xc6, 0xb1, 0x3e, 0x5a, 0x9b, 0xbf, 0xd9, 0x6d, 0x47, 0xd9, - 0xf4, 0xfe, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaa, 0x2d, 0x5d, 0xba, 0x43, 0x04, 0x00, 0x00, + 0xc5, 0x7a, 0xc5, 0x44, 0x5a, 0xe4, 0x71, 0x56, 0xe1, 0xbd, 0xbe, 0x36, 0xd4, 0x09, 0x34, 0xa3, + 0xa0, 0x1a, 0x7c, 0x00, 0xeb, 0x91, 0x83, 0x8e, 0x01, 0xcd, 0xc3, 0xab, 0x70, 0xfa, 0x2d, 0x8c, + 0xdd, 0xf9, 0x85, 0x3f, 0x8d, 0xe9, 0xf5, 0xcc, 0x73, 0x76, 0x90, 0x09, 0x7b, 0xae, 0x3b, 0x76, + 0x34, 0x55, 0x04, 0xc4, 0xd9, 0x1d, 0xfc, 0x31, 0xc0, 0x1e, 0x2f, 0x99, 0x68, 0xf6, 0x3e, 0x02, + 0x23, 0xb9, 0x2f, 0x92, 0x3b, 0xb5, 0xb5, 0x4e, 0xea, 0x06, 0xbd, 0x04, 0x4b, 0xa4, 0x19, 0xaf, + 0x04, 0xcb, 0x4a, 0xb5, 0xb8, 0x4e, 0xda, 0x81, 0xf4, 0x58, 0xf0, 0x9f, 0x42, 0x2d, 0x65, 0x11, + 0x55, 0xcb, 0x7d, 0x57, 0xbc, 0x2a, 0x8b, 0xbc, 0xe2, 0xb1, 0x28, 0xb0, 0xae, 0x8e, 0xa0, 0x19, + 0xd1, 0x02, 0xfd, 0x0f, 0x5d, 0x9e, 0x57, 0x71, 0xce, 0x32, 0x8e, 0x0d, 0x75, 0x6a, 0xf2, 0xbc, + 0x0a, 0x59, 0xc6, 0xd1, 0x09, 0x98, 0x2a, 0x06, 0xe9, 0x02, 0x77, 0xd4, 0x49, 0x47, 0xb6, 0xfe, + 0x02, 0x9d, 0x43, 0xef, 0x21, 0x1a, 0xb1, 0xb2, 0xd0, 0x54, 0x16, 0xfe, 0xd7, 0x5a, 0xf8, 0x70, + 0x0b, 0xe5, 0x9b, 0x9d, 0xb5, 0x0d, 0xba, 0x80, 0x5e, 0x52, 0xe4, 0x82, 0xe7, 0xa2, 0x66, 0x76, + 0x15, 0xf3, 0x4d, 0xcb, 0xdc, 0xf2, 0x60, 0x34, 0xae, 0x91, 0xb5, 0x4a, 0xd2, 0x36, 0xe8, 0x0c, + 0xcc, 0xaa, 0x8e, 0x1c, 0xb6, 0xfa, 0xda, 0xd0, 0x3e, 0xc5, 0xad, 0xc0, 0xd3, 0x2c, 0x5e, 0xee, + 0x90, 0x06, 0x8a, 0x46, 0x60, 0xa4, 0x32, 0x2e, 0x18, 0x14, 0xe7, 0xf8, 0x59, 0x8a, 0x5a, 0x46, + 0x0d, 0x93, 0x78, 0x26, 0x5f, 0x12, 0xdb, 0xcf, 0xf1, 0xdb, 0x09, 0x91, 0x78, 0x05, 0x43, 0xaf, + 0xc0, 0x4a, 0x8a, 0x2c, 0x5b, 0xe7, 0xa9, 0xd8, 0xe0, 0x9e, 0x0c, 0xdb, 0xe5, 0x0e, 0x69, 0x47, + 0xf2, 0x49, 0x6f, 0x57, 0x2c, 0x17, 0x78, 0x5f, 0x05, 0xb1, 0x6e, 0x06, 0xbf, 0x35, 0xb0, 0xb7, + 0x2e, 0x8a, 0x30, 0x1c, 0x35, 0x91, 0x19, 0x4f, 0x43, 0xea, 0x85, 0xb4, 0x09, 0xcd, 0x01, 0x00, + 0xf5, 0xbe, 0xd3, 0x78, 0xf6, 0xd9, 0xf5, 0x43, 0x47, 0x43, 0x36, 0x98, 0x11, 0xf5, 0xc7, 0x57, + 0x1e, 0x71, 0x76, 0x11, 0x40, 0x27, 0xa2, 0x2e, 0x9d, 0x47, 0xce, 0x1e, 0xb2, 0xc0, 0xf0, 0x82, + 0xe9, 0x27, 0xdf, 0xd1, 0xd1, 0x09, 0x1c, 0x52, 0xe2, 0x86, 0x91, 0x3b, 0xa6, 0xfe, 0x54, 0x2a, + 0x06, 0x81, 0x1b, 0x5e, 0x38, 0x06, 0x1a, 0xc2, 0xdb, 0xe8, 0x3a, 0xa2, 0x5e, 0x10, 0x07, 0x5e, + 0x14, 0xb9, 0x13, 0xef, 0xf1, 0x6b, 0x33, 0xe2, 0x7f, 0x75, 0xa9, 0x17, 0x4f, 0xc8, 0x74, 0x3e, + 0x73, 0x3a, 0x52, 0xcd, 0x0f, 0xdc, 0x89, 0xe7, 0x98, 0xb2, 0x54, 0x31, 0x76, 0xba, 0x68, 0x1f, + 0x2c, 0x29, 0x36, 0x0f, 0x7d, 0x7a, 0xed, 0x58, 0x32, 0xe8, 0xcf, 0xe4, 0x26, 0xee, 0xcc, 0x81, + 0x8f, 0xd6, 0xe3, 0xdf, 0xef, 0xa6, 0xa3, 0xec, 0x7b, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0x1b, + 0x8a, 0x21, 0xb0, 0x5b, 0x04, 0x00, 0x00, } diff --git a/protocol/protobuf/chat_message.proto b/protocol/protobuf/chat_message.proto index dbee7d9ba..3a8b4b672 100644 --- a/protocol/protobuf/chat_message.proto +++ b/protocol/protobuf/chat_message.proto @@ -70,5 +70,7 @@ message ChatMessage { IMAGE = 7; AUDIO = 8; COMMUNITY = 9; + // Only local + SYSTEM_MESSAGE_GAP = 10; } } diff --git a/protocol/protobuf/enums.pb.go b/protocol/protobuf/enums.pb.go index 8f400d318..6312bd2b2 100644 --- a/protocol/protobuf/enums.pb.go +++ b/protocol/protobuf/enums.pb.go @@ -30,6 +30,8 @@ const ( // Only local MessageType_SYSTEM_MESSAGE_PRIVATE_GROUP MessageType = 4 MessageType_COMMUNITY_CHAT MessageType = 5 + // Only local + MessageType_SYSTEM_MESSAGE_GAP MessageType = 6 ) var MessageType_name = map[int32]string{ @@ -39,6 +41,7 @@ var MessageType_name = map[int32]string{ 3: "PRIVATE_GROUP", 4: "SYSTEM_MESSAGE_PRIVATE_GROUP", 5: "COMMUNITY_CHAT", + 6: "SYSTEM_MESSAGE_GAP", } var MessageType_value = map[string]int32{ @@ -48,6 +51,7 @@ var MessageType_value = map[string]int32{ "PRIVATE_GROUP": 3, "SYSTEM_MESSAGE_PRIVATE_GROUP": 4, "COMMUNITY_CHAT": 5, + "SYSTEM_MESSAGE_GAP": 6, } func (x MessageType) String() string { @@ -103,19 +107,20 @@ func init() { } var fileDescriptor_888b6bd9597961ff = []byte{ - // 223 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x8f, 0xbd, 0x4e, 0xc3, 0x40, - 0x10, 0x84, 0x71, 0x6c, 0x48, 0xd8, 0x40, 0xb4, 0xac, 0x10, 0xa2, 0xa0, 0xa0, 0x4e, 0x41, 0xc3, - 0x13, 0x38, 0xd6, 0x72, 0x1c, 0x70, 0x3f, 0xca, 0xdd, 0x11, 0xb9, 0x3a, 0x11, 0xe9, 0xa0, 0x0a, - 0x89, 0x30, 0x2e, 0x78, 0x0d, 0x9e, 0x18, 0xd9, 0xc2, 0x88, 0x54, 0xbb, 0x1a, 0x8d, 0x66, 0xbe, - 0x81, 0x69, 0x7a, 0x6f, 0x37, 0xcd, 0xcd, 0xee, 0x63, 0xfb, 0xb9, 0xa5, 0x49, 0x7f, 0xd6, 0xed, - 0xeb, 0xfc, 0x3b, 0x83, 0xa9, 0x4a, 0x4d, 0xf3, 0xf2, 0x96, 0xfc, 0xd7, 0x2e, 0xd1, 0x25, 0x9c, - 0x07, 0xfd, 0xa8, 0xcd, 0x4a, 0x47, 0xc5, 0xce, 0x95, 0x82, 0xa3, 0xaf, 0x2d, 0xe3, 0x01, 0xcd, - 0x00, 0x8c, 0xe6, 0xe8, 0x4d, 0x34, 0x9a, 0x31, 0x23, 0x84, 0x13, 0x1b, 0x16, 0x4f, 0xb2, 0x8a, - 0x62, 0x69, 0x82, 0xc5, 0x11, 0x9d, 0xc1, 0xa9, 0x5d, 0xca, 0xe7, 0xd2, 0xf3, 0xaf, 0x94, 0xd3, - 0x35, 0x5c, 0xb9, 0xda, 0x79, 0x56, 0x7f, 0x69, 0xfb, 0x8e, 0x82, 0x08, 0x66, 0x95, 0x51, 0x2a, - 0x68, 0xe9, 0xeb, 0x58, 0xdd, 0x97, 0x1e, 0x0f, 0xe7, 0x12, 0x8e, 0xe5, 0x66, 0x20, 0xba, 0x00, - 0x1a, 0x88, 0xa4, 0xfa, 0xc7, 0x33, 0x86, 0xdc, 0x6a, 0x81, 0x19, 0x4d, 0xa0, 0x78, 0xb0, 0x2c, - 0x70, 0xd4, 0x7d, 0x2b, 0x5e, 0x74, 0xbd, 0x63, 0xc8, 0x85, 0xbc, 0xc3, 0x62, 0x7d, 0xd4, 0x2f, - 0xbd, 0xfd, 0x09, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x2a, 0x06, 0x76, 0xff, 0x00, 0x00, 0x00, + // 232 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0xd0, 0xcd, 0x4e, 0x02, 0x41, + 0x0c, 0x07, 0x70, 0x97, 0x5d, 0x01, 0x8b, 0x92, 0xda, 0x18, 0xe2, 0xc1, 0x83, 0x67, 0x0e, 0x5e, + 0x7c, 0x82, 0x61, 0x53, 0xc7, 0x51, 0xe7, 0x23, 0xcc, 0x8c, 0x64, 0x4f, 0x13, 0x49, 0x46, 0x4f, + 0x08, 0x71, 0xe5, 0xe0, 0x2b, 0xf9, 0x94, 0x06, 0xe2, 0x1a, 0xf5, 0xd4, 0xa6, 0x69, 0x9b, 0x5f, + 0xfe, 0x30, 0xca, 0xaf, 0xdb, 0x55, 0x7b, 0xb5, 0x79, 0x5b, 0xbf, 0xaf, 0x69, 0xb8, 0x2f, 0xcb, + 0xed, 0xf3, 0xf4, 0xb3, 0x80, 0x91, 0xce, 0x6d, 0xfb, 0xf4, 0x92, 0xc3, 0xc7, 0x26, 0xd3, 0x39, + 0x9c, 0x45, 0x73, 0x6f, 0xec, 0xc2, 0x24, 0xcd, 0xde, 0x0b, 0xc9, 0x29, 0x34, 0x8e, 0xf1, 0x80, + 0xc6, 0x00, 0xd6, 0x70, 0x0a, 0x36, 0x59, 0xc3, 0x58, 0x10, 0xc2, 0xb1, 0x8b, 0xb3, 0x07, 0x55, + 0x27, 0x39, 0xb7, 0xd1, 0x61, 0x8f, 0x4e, 0xe1, 0xc4, 0xcd, 0xd5, 0xa3, 0x08, 0xfc, 0x3d, 0x2a, + 0xe9, 0x12, 0x2e, 0x7c, 0xe3, 0x03, 0xeb, 0x9f, 0x6f, 0x7f, 0x37, 0x2a, 0x22, 0x18, 0xd7, 0x56, + 0xeb, 0x68, 0x54, 0x68, 0x52, 0x7d, 0x2b, 0x02, 0x1e, 0xd2, 0x04, 0xe8, 0xdf, 0x95, 0x14, 0x0e, + 0xfb, 0x53, 0x05, 0x47, 0x6a, 0xd5, 0x49, 0x27, 0x40, 0x9d, 0x54, 0xe9, 0x5f, 0xce, 0x01, 0x94, + 0xce, 0x48, 0x2c, 0x68, 0x08, 0xd5, 0x9d, 0x63, 0x89, 0xbd, 0x5d, 0xb7, 0xe0, 0xd9, 0xce, 0x33, + 0x80, 0x52, 0xaa, 0x1b, 0xac, 0x96, 0xfd, 0x7d, 0x02, 0xd7, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, + 0x39, 0x3a, 0x55, 0x56, 0x17, 0x01, 0x00, 0x00, } diff --git a/protocol/protobuf/enums.proto b/protocol/protobuf/enums.proto index 5de9022f2..95d298f0d 100644 --- a/protocol/protobuf/enums.proto +++ b/protocol/protobuf/enums.proto @@ -10,6 +10,8 @@ enum MessageType { // Only local SYSTEM_MESSAGE_PRIVATE_GROUP = 4; COMMUNITY_CHAT = 5; + // Only local + SYSTEM_MESSAGE_GAP = 6; } enum ImageType { diff --git a/protocol/pushnotificationclient/migrations/migrations.go b/protocol/pushnotificationclient/migrations/migrations.go index 7648f611d..9bd002b56 100644 --- a/protocol/pushnotificationclient/migrations/migrations.go +++ b/protocol/pushnotificationclient/migrations/migrations.go @@ -90,7 +90,7 @@ func _1593601729_initial_schemaDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1593601729_initial_schema.down.sql", size: 144, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1593601729_initial_schema.down.sql", size: 144, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa, 0x95, 0x55, 0x64, 0x38, 0x40, 0x16, 0xbf, 0x8b, 0x1c, 0x18, 0xb4, 0xc5, 0x7f, 0xd0, 0xb8, 0xf0, 0x3c, 0xa2, 0x82, 0xf8, 0x8d, 0x5a, 0xd3, 0xb6, 0x6e, 0xa3, 0xb4, 0xc, 0x9, 0x33, 0x0}} return a, nil } @@ -110,7 +110,7 @@ func _1593601729_initial_schemaUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1593601729_initial_schema.up.sql", size: 1773, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1593601729_initial_schema.up.sql", size: 1773, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4e, 0x1e, 0x5, 0x35, 0x9, 0xb2, 0x2d, 0x6f, 0x33, 0x63, 0xa2, 0x7a, 0x5b, 0xd2, 0x2d, 0xcb, 0x79, 0x7e, 0x6, 0xb4, 0x9d, 0x35, 0xd8, 0x9b, 0x55, 0xe5, 0xf8, 0x44, 0xca, 0xa6, 0xf3, 0xd3}} return a, nil } @@ -130,7 +130,7 @@ func _1597909626_add_server_typeDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1597909626_add_server_type.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1597909626_add_server_type.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}} return a, nil } @@ -150,7 +150,7 @@ func _1597909626_add_server_typeUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1597909626_add_server_type.up.sql", size: 145, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1597909626_add_server_type.up.sql", size: 145, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc8, 0x3f, 0xe0, 0xe7, 0x57, 0x0, 0x5d, 0x60, 0xf3, 0x55, 0x64, 0x71, 0x80, 0x3c, 0xca, 0x8, 0x61, 0xb5, 0x3c, 0xe, 0xa1, 0xe4, 0x61, 0xd1, 0x4e, 0xd8, 0xb2, 0x55, 0xdd, 0x87, 0x62, 0x9b}} return a, nil } @@ -170,7 +170,7 @@ func _1599053776_add_chat_id_and_typeDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1599053776_add_chat_id_and_type.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1599053776_add_chat_id_and_type.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}} return a, nil } @@ -190,7 +190,7 @@ func _1599053776_add_chat_id_and_typeUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1599053776_add_chat_id_and_type.up.sql", size: 264, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1599053776_add_chat_id_and_type.up.sql", size: 264, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x7a, 0xf9, 0xc4, 0xa2, 0x96, 0x2e, 0xf9, 0x8f, 0x7, 0xf1, 0x1e, 0x73, 0x8a, 0xa6, 0x3a, 0x13, 0x4, 0x73, 0x82, 0x83, 0xb, 0xe3, 0xb5, 0x3b, 0x7e, 0xd, 0x23, 0xce, 0x98, 0xd4, 0xdc}} return a, nil } @@ -210,7 +210,7 @@ func docGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "doc.go", size: 382, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "doc.go", size: 382, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc0, 0x2f, 0x1e, 0x64, 0x9, 0x93, 0xe4, 0x8b, 0xf2, 0x98, 0x5a, 0x45, 0xe2, 0x80, 0x88, 0x67, 0x7a, 0x2d, 0xd7, 0x4b, 0xd1, 0x73, 0xb6, 0x6d, 0x15, 0xc2, 0x0, 0x34, 0xcd, 0xa0, 0xdb, 0x20}} return a, nil } diff --git a/protocol/pushnotificationserver/migrations/migrations.go b/protocol/pushnotificationserver/migrations/migrations.go index 80abd1eb4..feb73a6aa 100644 --- a/protocol/pushnotificationserver/migrations/migrations.go +++ b/protocol/pushnotificationserver/migrations/migrations.go @@ -88,7 +88,7 @@ func _1593601728_initial_schemaDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1593601728_initial_schema.down.sql", size: 200, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1593601728_initial_schema.down.sql", size: 200, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x88, 0x8a, 0x61, 0x81, 0x57, 0x45, 0x9b, 0x97, 0x9b, 0x1f, 0xf6, 0x94, 0x8a, 0x20, 0xb3, 0x2b, 0xff, 0x69, 0x49, 0xf4, 0x58, 0xcc, 0xd0, 0x55, 0xcc, 0x9a, 0x8b, 0xb6, 0x7f, 0x29, 0x53, 0xc1}} return a, nil } @@ -108,7 +108,7 @@ func _1593601728_initial_schemaUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1593601728_initial_schema.up.sql", size: 675, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1593601728_initial_schema.up.sql", size: 675, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfd, 0x61, 0x90, 0x79, 0xd9, 0x14, 0x65, 0xe9, 0x96, 0x53, 0x17, 0x33, 0x54, 0xeb, 0x8b, 0x5d, 0x95, 0x99, 0x10, 0x36, 0x58, 0xdd, 0xb2, 0xbf, 0x45, 0xd9, 0xbb, 0xc4, 0x92, 0xe, 0xce, 0x2}} return a, nil } @@ -128,7 +128,7 @@ func _1598419937_add_push_notifications_tableDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1598419937_add_push_notifications_table.down.sql", size: 51, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1598419937_add_push_notifications_table.down.sql", size: 51, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x98, 0xc8, 0x30, 0x45, 0x5b, 0xc5, 0x7d, 0x13, 0x5d, 0xe7, 0xc8, 0x23, 0x43, 0xf7, 0xdc, 0x9c, 0xe2, 0xdd, 0x63, 0xf0, 0xb7, 0x16, 0x40, 0xc, 0xda, 0xb9, 0x16, 0x70, 0x2b, 0x5a, 0x7e}} return a, nil } @@ -148,7 +148,7 @@ func _1598419937_add_push_notifications_tableUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1598419937_add_push_notifications_table.up.sql", size: 104, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "1598419937_add_push_notifications_table.up.sql", size: 104, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2, 0x3e, 0xef, 0xf, 0xc2, 0xdf, 0xbc, 0x99, 0x7a, 0xc2, 0xd3, 0x64, 0x4f, 0x4c, 0x7e, 0xfc, 0x2e, 0x8c, 0xa7, 0x54, 0xd3, 0x4d, 0x25, 0x98, 0x41, 0xbc, 0xea, 0xd7, 0x2, 0xc1, 0xd0, 0x52}} return a, nil } @@ -168,7 +168,7 @@ func docGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "doc.go", size: 382, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "doc.go", size: 382, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc0, 0x2f, 0x1e, 0x64, 0x9, 0x93, 0xe4, 0x8b, 0xf2, 0x98, 0x5a, 0x45, 0xe2, 0x80, 0x88, 0x67, 0x7a, 0x2d, 0xd7, 0x4b, 0xd1, 0x73, 0xb6, 0x6d, 0x15, 0xc2, 0x0, 0x34, 0xcd, 0xa0, 0xdb, 0x20}} return a, nil } diff --git a/protocol/requests/clear_history.go b/protocol/requests/clear_history.go new file mode 100644 index 000000000..092a8d6d9 --- /dev/null +++ b/protocol/requests/clear_history.go @@ -0,0 +1,19 @@ +package requests + +import ( + "errors" +) + +var ErrClearHistoryInvalidID = errors.New("clear-history: invalid id") + +type ClearHistory struct { + ID string +} + +func (j *ClearHistory) Validate() error { + if len(j.ID) == 0 { + return ErrClearHistoryInvalidID + } + + return nil +} diff --git a/protocol/requests/create_profile_chat.go b/protocol/requests/create_profile_chat.go new file mode 100644 index 000000000..af5493664 --- /dev/null +++ b/protocol/requests/create_profile_chat.go @@ -0,0 +1,19 @@ +package requests + +import ( + "errors" +) + +var ErrCreateProfileChatInvalidID = errors.New("create-public-chat: invalid id") + +type CreateProfileChat struct { + ID string +} + +func (j *CreateProfileChat) Validate() error { + if len(j.ID) == 0 { + return ErrCreateProfileChatInvalidID + } + + return nil +} diff --git a/protocol/requests/create_public_chat.go b/protocol/requests/create_public_chat.go new file mode 100644 index 000000000..27e7ccc46 --- /dev/null +++ b/protocol/requests/create_public_chat.go @@ -0,0 +1,19 @@ +package requests + +import ( + "errors" +) + +var ErrCreatePublicChatInvalidID = errors.New("create-public-chat: invalid id") + +type CreatePublicChat struct { + ID string +} + +func (j *CreatePublicChat) Validate() error { + if len(j.ID) == 0 { + return ErrCreatePublicChatInvalidID + } + + return nil +} diff --git a/protocol/requests/deactivate_chat.go b/protocol/requests/deactivate_chat.go new file mode 100644 index 000000000..589ab9716 --- /dev/null +++ b/protocol/requests/deactivate_chat.go @@ -0,0 +1,19 @@ +package requests + +import ( + "errors" +) + +var ErrDeactivateChatInvalidID = errors.New("deactivate-chat: invalid id") + +type DeactivateChat struct { + ID string +} + +func (j *DeactivateChat) Validate() error { + if len(j.ID) == 0 { + return ErrDeactivateChatInvalidID + } + + return nil +} diff --git a/protocol/transport/filters_manager.go b/protocol/transport/filters_manager.go index ca3ff6c00..e2090dc31 100644 --- a/protocol/transport/filters_manager.go +++ b/protocol/transport/filters_manager.go @@ -225,6 +225,27 @@ func (f *FiltersManager) FilterByFilterID(filterID string) *Filter { return nil } +// FiltersByIdentities returns an array of filters for given list of public keys +func (f *FiltersManager) FiltersByIdentities(identities []string) []*Filter { + f.mutex.Lock() + defer f.mutex.Unlock() + + identitiesMap := make(map[string]bool) + + for _, identity := range identities { + identitiesMap[identity] = true + } + + var filters []*Filter + + for _, filter := range f.filters { + if identitiesMap[filter.Identity] { + filters = append(filters, filter) + } + } + return filters +} + // FilterByChatID returns a Filter for given chat id func (f *FiltersManager) FilterByChatID(chatID string) *Filter { f.mutex.Lock() @@ -233,20 +254,6 @@ func (f *FiltersManager) FilterByChatID(chatID string) *Filter { return f.filters[chatID] } -func (f *FiltersManager) FiltersByPublicKey(publicKey *ecdsa.PublicKey) (result []*Filter) { - f.mutex.Lock() - defer f.mutex.Unlock() - identityStr := PublicKeyToStr(publicKey) - - for _, f := range f.filters { - if f.Identity == identityStr { - result = append(result, f) - } - } - - return -} - // Remove remove all the filters associated with a chat/identity func (f *FiltersManager) Remove(filters ...*Filter) error { f.mutex.Lock() diff --git a/protocol/transport/migrations/migrations.go b/protocol/transport/migrations/migrations.go index ac15b7744..277b265ef 100644 --- a/protocol/transport/migrations/migrations.go +++ b/protocol/transport/migrations/migrations.go @@ -86,7 +86,7 @@ func _1561059284_add_waku_keysDownSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1561059284_add_waku_keys.down.sql", size: 22, mode: os.FileMode(0644), modTime: time.Unix(1621327524, 0)} + info := bindataFileInfo{name: "1561059284_add_waku_keys.down.sql", size: 22, mode: os.FileMode(0644), modTime: time.Unix(1621335496, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe5, 0x2a, 0x7e, 0x9, 0xa3, 0xdd, 0xc6, 0x3, 0xfa, 0xaa, 0x98, 0xa0, 0x26, 0x5e, 0x67, 0x43, 0xe6, 0x20, 0xfd, 0x10, 0xfd, 0x60, 0x89, 0x17, 0x13, 0x87, 0x1b, 0x44, 0x36, 0x79, 0xb6, 0x60}} return a, nil } @@ -106,7 +106,7 @@ func _1561059284_add_waku_keysUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1561059284_add_waku_keys.up.sql", size: 109, mode: os.FileMode(0644), modTime: time.Unix(1621327524, 0)} + info := bindataFileInfo{name: "1561059284_add_waku_keys.up.sql", size: 109, mode: os.FileMode(0644), modTime: time.Unix(1621335496, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x5c, 0x8, 0x32, 0xef, 0x12, 0x88, 0x21, 0xd, 0x7a, 0x42, 0x4d, 0xe7, 0x2d, 0x6c, 0x99, 0xb6, 0x1, 0xf1, 0xba, 0x2c, 0x40, 0x8d, 0xa9, 0x4b, 0xe6, 0xc4, 0x21, 0xec, 0x47, 0x6b, 0xf7}} return a, nil } @@ -126,7 +126,7 @@ func docGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "doc.go", size: 373, mode: os.FileMode(0644), modTime: time.Unix(1621327524, 0)} + info := bindataFileInfo{name: "doc.go", size: 373, mode: os.FileMode(0644), modTime: time.Unix(1621335496, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x23, 0x6a, 0xc1, 0xce, 0x94, 0xf6, 0xef, 0xf1, 0x97, 0x95, 0xb, 0x35, 0xaf, 0x5f, 0xe7, 0x5f, 0xac, 0x6e, 0xb8, 0xab, 0xba, 0xb5, 0x35, 0x97, 0x22, 0x36, 0x11, 0xce, 0x44, 0xfc, 0xfa, 0xac}} return a, nil } diff --git a/protocol/transport/processed_message_ids_cache.go b/protocol/transport/processed_message_ids_cache.go index e30e29b3f..c05100690 100644 --- a/protocol/transport/processed_message_ids_cache.go +++ b/protocol/transport/processed_message_ids_cache.go @@ -14,6 +14,11 @@ func NewProcessedMessageIDsCache(db *sql.DB) *ProcessedMessageIDsCache { return &ProcessedMessageIDsCache{db: db} } +func (c *ProcessedMessageIDsCache) Clear() error { + _, err := c.db.Exec("DELETE FROM transport_message_cache") + return err +} + func (c *ProcessedMessageIDsCache) Hits(ids []string) (map[string]bool, error) { hits := make(map[string]bool) idsArgs := make([]interface{}, 0, len(ids)) diff --git a/protocol/transport/transport.go b/protocol/transport/transport.go index 110ffe567..eb8a1199a 100644 --- a/protocol/transport/transport.go +++ b/protocol/transport/transport.go @@ -147,6 +147,10 @@ func (t *Transport) FilterByChatID(chatID string) *Filter { return t.filters.FilterByChatID(chatID) } +func (t *Transport) FiltersByIdentities(identities []string) []*Filter { + return t.filters.FiltersByIdentities(identities) +} + func (t *Transport) LoadFilters(filters []*Filter) ([]*Filter, error) { return t.filters.InitWithFilters(filters) } @@ -191,11 +195,6 @@ func (t *Transport) JoinPrivate(publicKey *ecdsa.PublicKey) (*Filter, error) { return t.filters.LoadContactCode(publicKey) } -func (t *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error { - filters := t.filters.FiltersByPublicKey(publicKey) - return t.filters.Remove(filters...) -} - func (t *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) ([]*Filter, error) { var filters []*Filter for _, pk := range publicKeys { @@ -209,16 +208,6 @@ func (t *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) ([]*Filter, error) return filters, nil } -func (t *Transport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error { - for _, publicKey := range publicKeys { - filters := t.filters.FiltersByPublicKey(publicKey) - if err := t.filters.Remove(filters...); err != nil { - return err - } - } - return nil -} - func (t *Transport) RetrieveRawAll() (map[Filter][]*types.Message, error) { result := make(map[Filter][]*types.Message) @@ -416,7 +405,7 @@ func (t *Transport) cleanFiltersLoop() { }() } -func (t *Transport) sendMessagesRequestForTopics( +func (t *Transport) SendMessagesRequestForTopics( ctx context.Context, peerID []byte, from, to uint32, @@ -464,7 +453,7 @@ func (t *Transport) SendMessagesRequest( topics = append(topics, f.Topic) } - return t.sendMessagesRequestForTopics(ctx, peerID, from, to, previousCursor, topics, waitForResponse) + return t.SendMessagesRequestForTopics(ctx, peerID, from, to, previousCursor, topics, waitForResponse) } func (t *Transport) SendMessagesRequestForFilter( @@ -479,7 +468,7 @@ func (t *Transport) SendMessagesRequestForFilter( topics := make([]types.TopicType, len(t.Filters())) topics = append(topics, filter.Topic) - return t.sendMessagesRequestForTopics(ctx, peerID, from, to, previousCursor, topics, waitForResponse) + return t.SendMessagesRequestForTopics(ctx, peerID, from, to, previousCursor, topics, waitForResponse) } func createMessagesRequest(from, to uint32, cursor []byte, topics []types.TopicType) types.MessagesRequest { @@ -549,6 +538,10 @@ func (t *Transport) SetEnvelopeEventsHandler(handler EnvelopeEventsHandler) erro return nil } +func (t *Transport) ClearProcessedMessageIDsCache() error { + return t.cache.Clear() +} + func PubkeyToHex(key *ecdsa.PublicKey) string { return types.EncodeHex(crypto.FromECDSAPub(key)) } diff --git a/protocol/transport/waku/waku_service.go b/protocol/transport/waku/waku_service.go new file mode 100644 index 000000000..da84a2382 --- /dev/null +++ b/protocol/transport/waku/waku_service.go @@ -0,0 +1,520 @@ +package waku + +import ( + "bytes" + "context" + "crypto/ecdsa" + "database/sql" + "sync" + "time" + + "github.com/pkg/errors" + "go.uber.org/zap" + + "github.com/status-im/status-go/eth-node/crypto" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/protocol/transport" +) + +var ( + // ErrNoMailservers returned if there is no configured mailservers that can be used. + ErrNoMailservers = errors.New("no configured mailservers") +) + +type wakuServiceKeysManager struct { + waku types.Waku + + // Identity of the current user. + privateKey *ecdsa.PrivateKey + + passToSymKeyMutex sync.RWMutex + passToSymKeyCache map[string]string +} + +func (m *wakuServiceKeysManager) AddOrGetKeyPair(priv *ecdsa.PrivateKey) (string, error) { + // caching is handled in waku + return m.waku.AddKeyPair(priv) +} + +func (m *wakuServiceKeysManager) AddOrGetSymKeyFromPassword(password string) (string, error) { + m.passToSymKeyMutex.Lock() + defer m.passToSymKeyMutex.Unlock() + + if val, ok := m.passToSymKeyCache[password]; ok { + return val, nil + } + + id, err := m.waku.AddSymKeyFromPassword(password) + if err != nil { + return id, err + } + + m.passToSymKeyCache[password] = id + + return id, nil +} + +func (m *wakuServiceKeysManager) RawSymKey(id string) ([]byte, error) { + return m.waku.GetSymKey(id) +} + +type Option func(*Transport) error + +// Transport is a transport based on Whisper service. +type Transport struct { + waku types.Waku + api types.PublicWakuAPI // only PublicWakuAPI implements logic to send messages + keysManager *wakuServiceKeysManager + filters *transport.FiltersManager + logger *zap.Logger + cache *transport.ProcessedMessageIDsCache + + mailservers []string + envelopesMonitor *EnvelopesMonitor + quit chan struct{} +} + +// NewTransport returns a new Transport. +// TODO: leaving a chat should verify that for a given public key +// there are no other chats. It may happen that we leave a private chat +// but still have a public chat for a given public key. +func NewTransport( + waku types.Waku, + privateKey *ecdsa.PrivateKey, + db *sql.DB, + mailservers []string, + envelopesMonitorConfig *transport.EnvelopesMonitorConfig, + logger *zap.Logger, + opts ...Option, +) (*Transport, error) { + filtersManager, err := transport.NewFiltersManager(newSQLitePersistence(db), waku, privateKey, logger) + if err != nil { + return nil, err + } + + var envelopesMonitor *EnvelopesMonitor + if envelopesMonitorConfig != nil { + envelopesMonitor = NewEnvelopesMonitor(waku, *envelopesMonitorConfig) + envelopesMonitor.Start() + } + + var api types.PublicWhisperAPI + if waku != nil { + api = waku.PublicWakuAPI() + } + t := &Transport{ + waku: waku, + api: api, + cache: transport.NewProcessedMessageIDsCache(db), + envelopesMonitor: envelopesMonitor, + quit: make(chan struct{}), + keysManager: &wakuServiceKeysManager{ + waku: waku, + privateKey: privateKey, + passToSymKeyCache: make(map[string]string), + }, + filters: filtersManager, + mailservers: mailservers, + logger: logger.With(zap.Namespace("Transport")), + } + + for _, opt := range opts { + if err := opt(t); err != nil { + return nil, err + } + } + + t.cleanFiltersLoop() + + return t, nil +} + +func (a *Transport) InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) { + return a.filters.Init(chatIDs, publicKeys) +} + +func (a *Transport) InitPublicFilters(chatIDs []string) ([]*transport.Filter, error) { + return a.filters.InitPublicFilters(chatIDs) +} + +func (a *Transport) Filters() []*transport.Filter { + return a.filters.Filters() +} + +func (a *Transport) FilterByChatID(chatID string) *transport.Filter { + return a.filters.FilterByChatID(chatID) +} + +func (a *Transport) LoadFilters(filters []*transport.Filter) ([]*transport.Filter, error) { + return a.filters.InitWithFilters(filters) +} + +func (a *Transport) InitCommunityFilters(pks []*ecdsa.PrivateKey) ([]*transport.Filter, error) { + return a.filters.InitCommunityFilters(pks) +} + +func (a *Transport) RemoveFilters(filters []*transport.Filter) error { + return a.filters.Remove(filters...) +} + +func (a *Transport) RemoveFilterByChatID(chatID string) (*transport.Filter, error) { + return a.filters.RemoveFilterByChatID(chatID) +} + +func (a *Transport) ResetFilters() error { + return a.filters.Reset() +} + +func (a *Transport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*transport.Filter, error) { + filter, err := a.filters.LoadNegotiated(secret) + if err != nil { + return nil, err + } + return filter, nil +} + +func (a *Transport) JoinPublic(chatID string) (*transport.Filter, error) { + return a.filters.LoadPublic(chatID) +} + +func (a *Transport) LeavePublic(chatID string) error { + chat := a.filters.Filter(chatID) + if chat != nil { + return nil + } + return a.filters.Remove(chat) +} + +func (a *Transport) JoinPrivate(publicKey *ecdsa.PublicKey) (*transport.Filter, error) { + return a.filters.LoadContactCode(publicKey) +} + +func (a *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error { + filters := a.filters.FiltersByPublicKey(publicKey) + return a.filters.Remove(filters...) +} + +func (a *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) { + var filters []*transport.Filter + for _, pk := range publicKeys { + f, err := a.filters.LoadContactCode(pk) + if err != nil { + return nil, err + } + filters = append(filters, f) + + } + return filters, nil +} + +func (a *Transport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error { + for _, publicKey := range publicKeys { + filters := a.filters.FiltersByPublicKey(publicKey) + if err := a.filters.Remove(filters...); err != nil { + return err + } + } + return nil +} + +func (a *Transport) RetrieveRawAll() (map[transport.Filter][]*types.Message, error) { + result := make(map[transport.Filter][]*types.Message) + + allFilters := a.filters.Filters() + for _, filter := range allFilters { + // Don't pull from filters we don't listen to + if !filter.Listen { + continue + } + msgs, err := a.api.GetFilterMessages(filter.FilterID) + if err != nil { + a.logger.Warn("failed to fetch messages", zap.Error(err)) + continue + } + if len(msgs) == 0 { + continue + } + + ids := make([]string, len(msgs)) + for i := range msgs { + id := types.EncodeHex(msgs[i].Hash) + ids[i] = id + } + + hits, err := a.cache.Hits(ids) + if err != nil { + a.logger.Error("failed to check messages exists", zap.Error(err)) + return nil, err + } + + for i := range msgs { + // Exclude anything that is a cache hit + if !hits[types.EncodeHex(msgs[i].Hash)] { + result[*filter] = append(result[*filter], msgs[i]) + } + } + + } + + return result, nil +} + +// SendPublic sends a new message using the Whisper service. +// For public filters, chat name is used as an ID as well as +// a topic. +func (a *Transport) SendPublic(ctx context.Context, newMessage *types.NewMessage, chatName string) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + filter, err := a.filters.LoadPublic(chatName) + if err != nil { + return nil, err + } + + newMessage.SymKeyID = filter.SymKeyID + newMessage.Topic = filter.Topic + + return a.api.Post(ctx, *newMessage) +} + +func (a *Transport) SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + filter, err := a.filters.LoadNegotiated(types.NegotiatedSecret{ + PublicKey: publicKey, + Key: secret, + }) + if err != nil { + return nil, err + } + + newMessage.SymKeyID = filter.SymKeyID + newMessage.Topic = filter.Topic + newMessage.PublicKey = nil + + return a.api.Post(ctx, *newMessage) +} + +func (a *Transport) SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + filter, err := a.filters.LoadPartitioned(publicKey, a.keysManager.privateKey, false) + if err != nil { + return nil, err + } + + newMessage.Topic = filter.Topic + newMessage.PublicKey = crypto.FromECDSAPub(publicKey) + + return a.api.Post(ctx, *newMessage) +} + +func (a *Transport) SendPrivateOnPersonalTopic(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + filter, err := a.filters.LoadPersonal(publicKey, a.keysManager.privateKey, false) + if err != nil { + return nil, err + } + + newMessage.Topic = filter.Topic + newMessage.PublicKey = crypto.FromECDSAPub(publicKey) + + return a.api.Post(ctx, *newMessage) +} + +func (a *Transport) LoadKeyFilters(key *ecdsa.PrivateKey) (*transport.Filter, error) { + return a.filters.LoadEphemeral(&key.PublicKey, key, true) +} + +func (a *Transport) SendCommunityMessage(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + // We load the filter to make sure we can post on it + filter, err := a.filters.LoadPublic(transport.PubkeyToHex(publicKey)[2:]) + if err != nil { + return nil, err + } + + newMessage.Topic = filter.Topic + newMessage.PublicKey = crypto.FromECDSAPub(publicKey) + + a.logger.Debug("SENDING message", zap.Binary("topic", filter.Topic[:])) + + return a.api.Post(ctx, *newMessage) +} + +func (a *Transport) cleanFilters() error { + return a.filters.RemoveNoListenFilters() +} + +func (a *Transport) addSig(newMessage *types.NewMessage) error { + sigID, err := a.keysManager.AddOrGetKeyPair(a.keysManager.privateKey) + if err != nil { + return err + } + newMessage.SigID = sigID + return nil +} + +func (a *Transport) Track(identifiers [][]byte, hash []byte, newMessage *types.NewMessage) { + if a.envelopesMonitor != nil { + a.envelopesMonitor.Add(identifiers, types.BytesToHash(hash), *newMessage) + } +} + +// GetCurrentTime returns the current unix timestamp in milliseconds +func (a *Transport) GetCurrentTime() uint64 { + return uint64(a.waku.GetCurrentTime().UnixNano() / int64(time.Millisecond)) +} + +func (a *Transport) MaxMessageSize() uint32 { + return a.waku.MaxMessageSize() +} + +func (a *Transport) Stop() error { + close(a.quit) + if a.envelopesMonitor != nil { + a.envelopesMonitor.Stop() + } + return nil +} + +// cleanFiltersLoop cleans up the topic we create for the only purpose +// of sending messages. +// Whenever we send a message we also need to listen to that particular topic +// but in case of asymettric topics, we are not interested in listening to them. +// We therefore periodically clean them up so we don't receive unnecessary data. + +func (a *Transport) cleanFiltersLoop() { + + ticker := time.NewTicker(5 * time.Minute) + go func() { + for { + select { + case <-a.quit: + ticker.Stop() + return + case <-ticker.C: + err := a.cleanFilters() + if err != nil { + a.logger.Error("failed to clean up topics", zap.Error(err)) + } + } + } + }() +} + +func (a *Transport) SendMessagesRequestForTopics( + ctx context.Context, + peerID []byte, + from, to uint32, + previousCursor []byte, + topics []types.TopicType, + waitForResponse bool, +) (cursor []byte, err error) { + + r := createMessagesRequest(from, to, previousCursor, topics) + r.SetDefaults(a.waku.GetCurrentTime()) + + events := make(chan types.EnvelopeEvent, 10) + sub := a.waku.SubscribeEnvelopeEvents(events) + defer sub.Unsubscribe() + + err = a.waku.SendMessagesRequest(peerID, r) + if err != nil { + return + } + + if !waitForResponse { + return + } + + resp, err := a.waitForRequestCompleted(ctx, r.ID, events) + if err == nil && resp != nil && resp.Error != nil { + err = resp.Error + } else if err == nil && resp != nil { + cursor = resp.Cursor + } + return +} + +// RequestHistoricMessages requests historic messages for all registered filters. +func (a *Transport) SendMessagesRequest( + ctx context.Context, + peerID []byte, + from, to uint32, + previousCursor []byte, + waitForResponse bool, +) (cursor []byte, err error) { + + topics := make([]types.TopicType, len(a.Filters())) + for _, f := range a.Filters() { + topics = append(topics, f.Topic) + } + + return a.SendMessagesRequestForTopics(ctx, peerID, from, to, previousCursor, topics, waitForResponse) +} + +func (a *Transport) SendMessagesRequestForFilter( + ctx context.Context, + peerID []byte, + from, to uint32, + previousCursor []byte, + filter *transport.Filter, + waitForResponse bool, +) (cursor []byte, err error) { + + topics := make([]types.TopicType, len(a.Filters())) + topics = append(topics, filter.Topic) + + return a.SendMessagesRequestForTopics(ctx, peerID, from, to, previousCursor, topics, waitForResponse) +} + +func (a *Transport) waitForRequestCompleted(ctx context.Context, requestID []byte, events chan types.EnvelopeEvent) (*types.MailServerResponse, error) { + for { + select { + case ev := <-events: + if !bytes.Equal(ev.Hash.Bytes(), requestID) { + continue + } + if ev.Event != types.EventMailServerRequestCompleted { + continue + } + data, ok := ev.Data.(*types.MailServerResponse) + if ok { + return data, nil + } + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +// ConfirmMessagesProcessed marks the messages as processed in the cache so +// they won't be passed to the next layer anymore +func (a *Transport) ConfirmMessagesProcessed(ids []string, timestamp uint64) error { + return a.cache.Add(ids, timestamp) +} + +// CleanMessagesProcessed clears the messages that are older than timestamp +func (a *Transport) CleanMessagesProcessed(timestamp uint64) error { + return a.cache.Clean(timestamp) +} + +func (a *Transport) SetEnvelopeEventsHandler(handler transport.EnvelopeEventsHandler) error { + if a.envelopesMonitor == nil { + return errors.New("Current transport has no envelopes monitor") + } + a.envelopesMonitor.handler = handler + return nil +} diff --git a/protocol/transport/whisper/migrations/migrations.go b/protocol/transport/whisper/migrations/migrations.go index afb6e9d76..5cc3292a8 100644 --- a/protocol/transport/whisper/migrations/migrations.go +++ b/protocol/transport/whisper/migrations/migrations.go @@ -86,7 +86,11 @@ func _1561059285_add_whisper_keysDownSql() (*asset, error) { return nil, err } +<<<<<<< HEAD info := bindataFileInfo{name: "1561059285_add_whisper_keys.down.sql", size: 25, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)} +======= + info := bindataFileInfo{name: "1561059285_add_whisper_keys.down.sql", size: 25, mode: os.FileMode(0644), modTime: time.Unix(1619180307, 0)} +>>>>>>> 21a705ec (create gaps) a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb9, 0x31, 0x3f, 0xce, 0xfa, 0x44, 0x36, 0x1b, 0xb0, 0xec, 0x5d, 0xb, 0x90, 0xb, 0x21, 0x4f, 0xd5, 0xe5, 0x50, 0xed, 0xc7, 0x43, 0xdf, 0x83, 0xb4, 0x3a, 0xc1, 0x55, 0x2e, 0x53, 0x7c, 0x67}} return a, nil } @@ -106,7 +110,11 @@ func _1561059285_add_whisper_keysUpSql() (*asset, error) { return nil, err } +<<<<<<< HEAD info := bindataFileInfo{name: "1561059285_add_whisper_keys.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)} +======= + info := bindataFileInfo{name: "1561059285_add_whisper_keys.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1619180307, 0)} +>>>>>>> 21a705ec (create gaps) a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x25, 0x41, 0xc, 0x92, 0xdd, 0x9e, 0xff, 0x5d, 0xd0, 0x93, 0xe4, 0x24, 0x50, 0x29, 0xcf, 0xc6, 0xf7, 0x49, 0x3c, 0x73, 0xd9, 0x8c, 0xfa, 0xf2, 0xcf, 0xf6, 0x6f, 0xbc, 0x31, 0xe6, 0xf7, 0xe2}} return a, nil } @@ -126,7 +134,11 @@ func docGo() (*asset, error) { return nil, err } +<<<<<<< HEAD info := bindataFileInfo{name: "doc.go", size: 373, mode: os.FileMode(0644), modTime: time.Unix(1607354881, 0)} +======= + info := bindataFileInfo{name: "doc.go", size: 373, mode: os.FileMode(0644), modTime: time.Unix(1619180307, 0)} +>>>>>>> 21a705ec (create gaps) a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x23, 0x6a, 0xc1, 0xce, 0x94, 0xf6, 0xef, 0xf1, 0x97, 0x95, 0xb, 0x35, 0xaf, 0x5f, 0xe7, 0x5f, 0xac, 0x6e, 0xb8, 0xab, 0xba, 0xb5, 0x35, 0x97, 0x22, 0x36, 0x11, 0xce, 0x44, 0xfc, 0xfa, 0xac}} return a, nil } diff --git a/protocol/transport/whisper/whisper_service.go b/protocol/transport/whisper/whisper_service.go new file mode 100644 index 000000000..b731c6e33 --- /dev/null +++ b/protocol/transport/whisper/whisper_service.go @@ -0,0 +1,525 @@ +package whisper + +import ( + "bytes" + "context" + "crypto/ecdsa" + "database/sql" + "sync" + "time" + + "github.com/pkg/errors" + "go.uber.org/zap" + + "github.com/status-im/status-go/eth-node/crypto" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/protocol/transport" +) + +var ( + // ErrNoMailservers returned if there is no configured mailservers that can be used. + ErrNoMailservers = errors.New("no configured mailservers") +) + +type whisperServiceKeysManager struct { + shh types.Whisper + + // Identity of the current user. + privateKey *ecdsa.PrivateKey + + passToSymKeyMutex sync.RWMutex + passToSymKeyCache map[string]string +} + +func (m *whisperServiceKeysManager) AddOrGetKeyPair(priv *ecdsa.PrivateKey) (string, error) { + // caching is handled in Whisper + return m.shh.AddKeyPair(priv) +} + +func (m *whisperServiceKeysManager) AddOrGetSymKeyFromPassword(password string) (string, error) { + m.passToSymKeyMutex.Lock() + defer m.passToSymKeyMutex.Unlock() + + if val, ok := m.passToSymKeyCache[password]; ok { + return val, nil + } + + id, err := m.shh.AddSymKeyFromPassword(password) + if err != nil { + return id, err + } + + m.passToSymKeyCache[password] = id + + return id, nil +} + +func (m *whisperServiceKeysManager) RawSymKey(id string) ([]byte, error) { + return m.shh.GetSymKey(id) +} + +type Option func(*Transport) error + +// Transport is a transport based on Whisper service. +type Transport struct { + shh types.Whisper + shhAPI types.PublicWhisperAPI // only PublicWhisperAPI implements logic to send messages + keysManager *whisperServiceKeysManager + filters *transport.FiltersManager + logger *zap.Logger + + mailservers []string + envelopesMonitor *EnvelopesMonitor +} + +// NewTransport returns a new Transport. +// TODO: leaving a chat should verify that for a given public key +// there are no other chats. It may happen that we leave a private chat +// but still have a public chat for a given public key. +func NewTransport( + shh types.Whisper, + privateKey *ecdsa.PrivateKey, + db *sql.DB, + mailservers []string, + envelopesMonitorConfig *transport.EnvelopesMonitorConfig, + logger *zap.Logger, + opts ...Option, +) (*Transport, error) { + filtersManager, err := transport.NewFiltersManager(newSQLitePersistence(db), shh, privateKey, logger) + if err != nil { + return nil, err + } + + var envelopesMonitor *EnvelopesMonitor + if envelopesMonitorConfig != nil { + envelopesMonitor = NewEnvelopesMonitor(shh, *envelopesMonitorConfig) + envelopesMonitor.Start() + } + + var shhAPI types.PublicWhisperAPI + if shh != nil { + shhAPI = shh.PublicWhisperAPI() + } + t := &Transport{ + shh: shh, + shhAPI: shhAPI, + envelopesMonitor: envelopesMonitor, + keysManager: &whisperServiceKeysManager{ + shh: shh, + privateKey: privateKey, + passToSymKeyCache: make(map[string]string), + }, + filters: filtersManager, + mailservers: mailservers, + logger: logger.With(zap.Namespace("Transport")), + } + + for _, opt := range opts { + if err := opt(t); err != nil { + return nil, err + } + } + + return t, nil +} + +func (a *Transport) InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) { + return a.filters.Init(chatIDs, publicKeys) +} + +func (a *Transport) InitPublicFilters(chatIDs []string) ([]*transport.Filter, error) { + return a.filters.InitPublicFilters(chatIDs) +} + +func (a *Transport) InitCommunityFilters(pks []*ecdsa.PrivateKey) ([]*transport.Filter, error) { + return a.filters.InitCommunityFilters(pks) +} + +func (a *Transport) Filters() []*transport.Filter { + return a.filters.Filters() +} + +func (a *Transport) FilterByChatID(chatID string) *transport.Filter { + return a.filters.FilterByChatID(chatID) +} + +func (a *Transport) LoadFilters(filters []*transport.Filter) ([]*transport.Filter, error) { + return a.filters.InitWithFilters(filters) +} + +func (a *Transport) SendCommunityMessage(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + // We load the filter to make sure we can post on it + filter, err := a.filters.LoadPublic(transport.PubkeyToHex(publicKey)) + if err != nil { + return nil, err + } + + newMessage.Topic = filter.Topic + newMessage.PublicKey = crypto.FromECDSAPub(publicKey) + + return a.shhAPI.Post(ctx, *newMessage) +} + +func (a *Transport) RemoveFilters(filters []*transport.Filter) error { + return a.filters.Remove(filters...) +} + +func (a *Transport) RemoveFilterByChatID(chatID string) (*transport.Filter, error) { + return a.filters.RemoveFilterByChatID(chatID) +} + +func (a *Transport) ResetFilters() error { + return a.filters.Reset() +} + +func (a *Transport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*transport.Filter, error) { + filter, err := a.filters.LoadNegotiated(secret) + if err != nil { + return nil, err + } + return filter, nil +} + +func (a *Transport) JoinPublic(chatID string) (*transport.Filter, error) { + return a.filters.LoadPublic(chatID) +} + +func (a *Transport) LeavePublic(chatID string) error { + chat := a.filters.Filter(chatID) + if chat != nil { + return nil + } + return a.filters.Remove(chat) +} + +func (a *Transport) JoinPrivate(publicKey *ecdsa.PublicKey) (*transport.Filter, error) { + return a.filters.LoadContactCode(publicKey) +} + +func (a *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error { + filters := a.filters.FiltersByPublicKey(publicKey) + return a.filters.Remove(filters...) +} + +func (a *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) { + var filters []*transport.Filter + for _, pk := range publicKeys { + f, err := a.filters.LoadContactCode(pk) + if err != nil { + return nil, err + } + filters = append(filters, f) + } + return filters, nil +} + +func (a *Transport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error { + for _, publicKey := range publicKeys { + filters := a.filters.FiltersByPublicKey(publicKey) + if err := a.filters.Remove(filters...); err != nil { + return err + } + } + return nil +} + +type Message struct { + Message *types.Message + Public bool +} + +func (a *Transport) RetrieveAllMessages() ([]Message, error) { + var messages []Message + + for _, filter := range a.filters.Filters() { + filterMsgs, err := a.shhAPI.GetFilterMessages(filter.FilterID) + if err != nil { + return nil, err + } + + for _, m := range filterMsgs { + messages = append(messages, Message{ + Message: m, + Public: filter.IsPublic(), + }) + } + } + + return messages, nil +} + +func (a *Transport) RetrievePublicMessages(chatID string) ([]*types.Message, error) { + filter, err := a.filters.LoadPublic(chatID) + if err != nil { + return nil, err + } + + return a.shhAPI.GetFilterMessages(filter.FilterID) +} + +func (a *Transport) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]*types.Message, error) { + chats := a.filters.FiltersByPublicKey(publicKey) + discoveryChats, err := a.filters.Init(nil, nil) + if err != nil { + return nil, err + } + + var result []*types.Message + + for _, chat := range append(chats, discoveryChats...) { + filterMsgs, err := a.shhAPI.GetFilterMessages(chat.FilterID) + if err != nil { + return nil, err + } + + result = append(result, filterMsgs...) + } + + return result, nil +} + +func (a *Transport) RetrieveRawAll() (map[transport.Filter][]*types.Message, error) { + result := make(map[transport.Filter][]*types.Message) + + allFilters := a.filters.Filters() + for _, filter := range allFilters { + msgs, err := a.shhAPI.GetFilterMessages(filter.FilterID) + if err != nil { + continue + } + result[*filter] = append(result[*filter], msgs...) + } + + return result, nil +} + +// SendPublic sends a new message using the Whisper service. +// For public filters, chat name is used as an ID as well as +// a topic. +func (a *Transport) SendPublic(ctx context.Context, newMessage *types.NewMessage, chatName string) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + filter, err := a.filters.LoadPublic(chatName) + if err != nil { + return nil, err + } + + newMessage.SymKeyID = filter.SymKeyID + newMessage.Topic = filter.Topic + + return a.shhAPI.Post(ctx, *newMessage) +} + +func (a *Transport) SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + filter, err := a.filters.LoadNegotiated(types.NegotiatedSecret{ + PublicKey: publicKey, + Key: secret, + }) + if err != nil { + return nil, err + } + + newMessage.SymKeyID = filter.SymKeyID + newMessage.Topic = filter.Topic + newMessage.PublicKey = nil + + return a.shhAPI.Post(ctx, *newMessage) +} + +func (a *Transport) SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + filter, err := a.filters.LoadPartitioned(publicKey, a.keysManager.privateKey, false) + if err != nil { + return nil, err + } + + newMessage.Topic = filter.Topic + newMessage.PublicKey = crypto.FromECDSAPub(publicKey) + + return a.shhAPI.Post(ctx, *newMessage) +} + +func (a *Transport) SendPrivateOnPersonalTopic(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + filter, err := a.filters.LoadPersonal(publicKey, a.keysManager.privateKey, false) + if err != nil { + return nil, err + } + + newMessage.Topic = filter.Topic + newMessage.PublicKey = crypto.FromECDSAPub(publicKey) + + return a.shhAPI.Post(ctx, *newMessage) +} + +func (a *Transport) SendPrivateOnDiscovery(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) { + if err := a.addSig(newMessage); err != nil { + return nil, err + } + + // There is no need to load any chat + // because listening on the discovery topic + // is done automatically. + // TODO: change this anyway, it should be explicit + // and idempotent. + + newMessage.Topic = types.BytesToTopic(transport.ToTopic(transport.DiscoveryTopic())) + newMessage.PublicKey = crypto.FromECDSAPub(publicKey) + + return a.shhAPI.Post(ctx, *newMessage) +} + +func (a *Transport) addSig(newMessage *types.NewMessage) error { + sigID, err := a.keysManager.AddOrGetKeyPair(a.keysManager.privateKey) + if err != nil { + return err + } + newMessage.SigID = sigID + return nil +} + +func (a *Transport) Track(identifiers [][]byte, hash []byte, newMessage *types.NewMessage) { + if a.envelopesMonitor != nil { + a.envelopesMonitor.Add(identifiers, types.BytesToHash(hash), *newMessage) + } +} + +// GetCurrentTime returns the current unix timestamp in milliseconds +func (a *Transport) GetCurrentTime() uint64 { + return uint64(a.shh.GetCurrentTime().UnixNano() / int64(time.Millisecond)) +} + +func (a *Transport) MaxMessageSize() uint32 { + return a.shh.MaxMessageSize() +} + +func (a *Transport) Stop() error { + if a.envelopesMonitor != nil { + a.envelopesMonitor.Stop() + } + return nil +} + +// RequestHistoricMessages requests historic messages for all registered filters. +func (a *Transport) SendMessagesRequest( + ctx context.Context, + peerID []byte, + from, to uint32, + previousCursor []byte, + waitForResponse bool, +) (cursor []byte, err error) { + topics := make([]types.TopicType, len(a.Filters())) + for _, f := range a.Filters() { + topics = append(topics, f.Topic) + } + + r := createMessagesRequest(from, to, previousCursor, topics) + r.SetDefaults(a.shh.GetCurrentTime()) + + events := make(chan types.EnvelopeEvent, 10) + sub := a.shh.SubscribeEnvelopeEvents(events) + defer sub.Unsubscribe() + + err = a.shh.SendMessagesRequest(peerID, r) + if err != nil { + return + } + + if !waitForResponse { + return + } + + resp, err := a.waitForRequestCompleted(ctx, r.ID, events) + if err == nil && resp != nil && resp.Error != nil { + err = resp.Error + } else if err == nil && resp != nil { + cursor = resp.Cursor + } + return +} + +//TODO: kozieiev: fix +func (a *Transport) SendMessagesRequestForFilter( + ctx context.Context, + peerID []byte, + from, to uint32, + previousCursor []byte, + filter *transport.Filter, + waitForResponse bool, +) (cursor []byte, err error) { + return nil, nil +} + +func (a *Transport) SendMessagesRequestForTopics( + ctx context.Context, + peerID []byte, + from, to uint32, + previousCursor []byte, + topics []types.TopicType, + waitForResponse bool, +) (cursor []byte, err error) { + return nil, nil +} + +func (a *Transport) LoadKeyFilters(key *ecdsa.PrivateKey) (*transport.Filter, error) { + return a.filters.LoadPartitioned(&key.PublicKey, key, true) +} + +func (a *Transport) waitForRequestCompleted(ctx context.Context, requestID []byte, events chan types.EnvelopeEvent) (*types.MailServerResponse, error) { + for { + select { + case ev := <-events: + a.logger.Debug( + "waiting for request completed and received an event", + zap.Binary("requestID", requestID), + zap.Any("event", ev), + ) + if !bytes.Equal(ev.Hash.Bytes(), requestID) { + continue + } + if ev.Event != types.EventMailServerRequestCompleted { + continue + } + data, ok := ev.Data.(*types.MailServerResponse) + if ok { + return data, nil + } + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +// NOTE: currently not used as whisper is not maintained anymore +func (a *Transport) ConfirmMessagesProcessed(ids []string, timestamp uint64) error { + return nil +} + +// NOTE: currently not used as whisper is not maintained anymore +func (a *Transport) CleanMessagesProcessed(timestamp uint64) error { + return nil +} + +func (a *Transport) SetEnvelopeEventsHandler(handler transport.EnvelopeEventsHandler) error { + if a.envelopesMonitor == nil { + return errors.New("Current transport has no envelopes monitor") + } + a.envelopesMonitor.handler = handler + return nil +} diff --git a/services/ext/api.go b/services/ext/api.go index 9b2a7ef82..e8a06d36d 100644 --- a/services/ext/api.go +++ b/services/ext/api.go @@ -187,24 +187,6 @@ type Metadata struct { Author Author `json:"author"` } -// ConfirmMessagesProcessedByID is a method to confirm that messages was consumed by -// the client side. -// TODO: this is broken now as it requires dedup ID while a message hash should be used. -func (api *PublicAPI) ConfirmMessagesProcessedByID(messageConfirmations []*Metadata) error { - confirmationCount := len(messageConfirmations) - dedupIDs := make([][]byte, confirmationCount) - encryptionIDs := make([][]byte, confirmationCount) - for i, confirmation := range messageConfirmations { - dedupIDs[i] = confirmation.DedupID - encryptionIDs[i] = confirmation.EncryptionID - } - return api.service.ConfirmMessagesProcessed(encryptionIDs) -} - -func (api *PublicAPI) Leave(chat protocol.Chat) error { - return api.service.messenger.Leave(chat) -} - func (api *PublicAPI) LeaveGroupChat(ctx Context, chatID string, remove bool) (*protocol.MessengerResponse, error) { return api.service.messenger.LeaveGroupChat(ctx, chatID, remove) } @@ -261,6 +243,14 @@ func (api *PublicAPI) CreateOneToOneChat(parent context.Context, request *reques return api.service.messenger.CreateOneToOneChat(request) } +func (api *PublicAPI) CreatePublicChat(parent context.Context, request *requests.CreatePublicChat) (*protocol.MessengerResponse, error) { + return api.service.messenger.CreatePublicChat(request) +} + +func (api *PublicAPI) CreateProfileChat(parent context.Context, request *requests.CreateProfileChat) (*protocol.MessengerResponse, error) { + return api.service.messenger.CreateProfileChat(request) +} + func (api *PublicAPI) Chats(parent context.Context) []*protocol.Chat { return api.service.messenger.Chats() } @@ -484,12 +474,12 @@ func (api *PublicAPI) RemoveContact(ctx context.Context, pubKey string) (*protoc return api.service.messenger.RemoveContact(ctx, pubKey) } -func (api *PublicAPI) ClearHistory(chatID string) (*protocol.MessengerResponse, error) { - return api.service.messenger.ClearHistory(chatID) +func (api *PublicAPI) ClearHistory(request *requests.ClearHistory) (*protocol.MessengerResponse, error) { + return api.service.messenger.ClearHistory(request) } -func (api *PublicAPI) DeactivateChat(chatID string) (*protocol.MessengerResponse, error) { - return api.service.messenger.DeactivateChat(chatID) +func (api *PublicAPI) DeactivateChat(request *requests.DeactivateChat) (*protocol.MessengerResponse, error) { + return api.service.messenger.DeactivateChat(request) } func (api *PublicAPI) UpdateMessageOutgoingStatus(id, newOutgoingStatus string) error { @@ -757,11 +747,23 @@ func (api *PublicAPI) ActivityCenterNotifications(cursor string, limit uint64) ( return api.service.messenger.ActivityCenterNotifications(cursor, limit) } +func (api *PublicAPI) RequestAllHistoricMessages() (*protocol.MessengerResponse, error) { + return api.service.messenger.RequestAllHistoricMessages() +} + // Echo is a method for testing purposes. func (api *PublicAPI) Echo(ctx context.Context, message string) (string, error) { return message, nil } +func (api *PublicAPI) FillGaps(chatID string, messageIDs []string) error { + return api.service.messenger.FillGaps(chatID, messageIDs) +} + +func (api *PublicAPI) SyncChatFromSyncedFrom(chatID string) (uint32, error) { + return api.service.messenger.SyncChatFromSyncedFrom(chatID) +} + // ----- // HELPER // ----- diff --git a/services/ext/service.go b/services/ext/service.go index 9c216bbd1..fea0ca318 100644 --- a/services/ext/service.go +++ b/services/ext/service.go @@ -34,7 +34,6 @@ import ( localnotifications "github.com/status-im/status-go/services/local-notifications" mailserversDB "github.com/status-im/status-go/services/mailservers" "github.com/status-im/status-go/services/wallet" - "github.com/status-im/status-go/signal" "go.uber.org/zap" ) @@ -315,10 +314,6 @@ func (s *Service) verifyTransactionLoop(tick time.Duration, cancel <-chan struct } } -func (s *Service) ConfirmMessagesProcessed(messageIDs [][]byte) error { - return s.messenger.ConfirmMessagesProcessed(messageIDs) -} - func (s *Service) EnableInstallation(installationID string) error { return s.messenger.EnableInstallation(installationID) } @@ -330,7 +325,9 @@ func (s *Service) DisableInstallation(installationID string) error { // UpdateMailservers updates information about selected mail servers. func (s *Service) UpdateMailservers(nodes []*enode.Node) error { + log.Info("updating nodes", "nodes", nodes, "messenger", s.messenger) if len(nodes) > 0 && s.messenger != nil { + log.Info("Setting messenger") s.messenger.SetMailserver(nodes[0].ID().Bytes()) } if err := s.peerStore.Update(nodes); err != nil { @@ -412,27 +409,6 @@ func (s *Service) Stop() error { return nil } -func onNegotiatedFilters(filters []*transport.Filter) { - var signalFilters []*signal.Filter - for _, filter := range filters { - - signalFilter := &signal.Filter{ - ChatID: filter.ChatID, - SymKeyID: filter.SymKeyID, - Listen: filter.Listen, - FilterID: filter.FilterID, - Identity: filter.Identity, - Topic: filter.Topic, - } - - signalFilters = append(signalFilters, signalFilter) - } - if len(filters) != 0 { - handler := PublisherSignalHandler{} - handler.FilterAdded(signalFilters) - } -} - func buildMessengerOptions( config params.ShhextConfig, identity *ecdsa.PrivateKey, @@ -452,7 +428,6 @@ func buildMessengerOptions( protocol.WithMailserversDatabase(mailserversDB.NewDB(db)), protocol.WithAccount(account), protocol.WithEnvelopesMonitorConfig(envelopesMonitorConfig), - protocol.WithOnNegotiatedFilters(onNegotiatedFilters), protocol.WithSignalsHandler(messengerSignalsHandler), protocol.WithENSVerificationConfig(publishMessengerResponse, config.VerifyENSURL, config.VerifyENSContractAddress), } diff --git a/services/ext/signal.go b/services/ext/signal.go index fbe3f516f..0f69f79db 100644 --- a/services/ext/signal.go +++ b/services/ext/signal.go @@ -41,11 +41,6 @@ func (h PublisherSignalHandler) BundleAdded(identity string, installationID stri signal.SendBundleAdded(identity, installationID) } -func (h PublisherSignalHandler) FilterAdded(filters []*signal.Filter) { - // TODO(waku): change the name of the filter to generic one. - signal.SendWhisperFilterAdded(filters) -} - func (h PublisherSignalHandler) NewMessages(response *protocol.MessengerResponse) { signal.SendNewMessages(response) } @@ -62,3 +57,7 @@ func (m MessengerSignalsHandler) MessageDelivered(chatID string, messageID strin func (m MessengerSignalsHandler) CommunityInfoFound(community *communities.Community) { signal.SendCommunityInfoFound(community) } + +func (m *MessengerSignalsHandler) MessengerResponse(response *protocol.MessengerResponse) { + PublisherSignalHandler{}.NewMessages(response) +} diff --git a/signal/events_shhext.go b/signal/events_shhext.go index cd5d9561b..0c1518383 100644 --- a/signal/events_shhext.go +++ b/signal/events_shhext.go @@ -32,9 +32,6 @@ const ( // EventBundleAdded is triggered when we receive a bundle EventBundleAdded = "bundles.added" - // EventWhisperFilterAdded is triggered when we setup a new filter or restore existing ones - EventWhisperFilterAdded = "whisper.filter.added" - // EventNewMessages is triggered when we receive new messages EventNewMessages = "messages.new" ) @@ -80,10 +77,6 @@ type Filter struct { Topic types.TopicType `json:"topic"` } -type WhisperFilterAddedSignal struct { - Filters []*Filter `json:"filters"` -} - // SendEnvelopeSent triggered when envelope delivered at least to 1 peer. func SendEnvelopeSent(identifiers [][]byte) { var hexIdentifiers []hexutil.Bytes @@ -153,10 +146,6 @@ func SendBundleAdded(identity string, installationID string) { send(EventBundleAdded, BundleAddedSignal{Identity: identity, InstallationID: installationID}) } -func SendWhisperFilterAdded(filters []*Filter) { - send(EventWhisperFilterAdded, WhisperFilterAddedSignal{Filters: filters}) -} - func SendNewMessages(obj json.Marshaler) { send(EventNewMessages, obj) } diff --git a/static/bindata.go b/static/bindata.go index a6f9bdac9..189d77edd 100644 --- a/static/bindata.go +++ b/static/bindata.go @@ -97,7 +97,7 @@ func ConfigReadmeMd() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "../config/README.md", size: 3153, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "../config/README.md", size: 3153, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x84, 0xf1, 0x44, 0x5b, 0x33, 0xe5, 0xfa, 0xe6, 0x38, 0x77, 0x19, 0x91, 0x6e, 0xd8, 0x8e, 0x8d, 0xaa, 0x32, 0xb2, 0x8b, 0xf9, 0x4f, 0x3, 0xe, 0xc0, 0xca, 0x5e, 0x5d, 0xec, 0x37, 0x1d, 0xc3}} return a, nil } @@ -117,7 +117,7 @@ func ConfigCliFleetEthProdJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "../config/cli/fleet-eth.prod.json", size: 4925, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "../config/cli/fleet-eth.prod.json", size: 4925, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x97, 0x5a, 0x72, 0x64, 0x6b, 0xee, 0xe6, 0x97, 0xda, 0xe8, 0x53, 0x7c, 0x33, 0x25, 0x27, 0x55, 0xa8, 0xe0, 0x9a, 0xc2, 0x16, 0xcf, 0xc0, 0x91, 0x8a, 0xbc, 0x98, 0x5, 0xe5, 0x63, 0x83, 0x77}} return a, nil } @@ -137,7 +137,7 @@ func ConfigCliFleetEthStagingJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "../config/cli/fleet-eth.staging.json", size: 2307, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "../config/cli/fleet-eth.staging.json", size: 2307, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa, 0x55, 0x35, 0x5e, 0xf5, 0x90, 0x37, 0x0, 0xe4, 0x45, 0x8c, 0x19, 0x77, 0x14, 0xa0, 0x94, 0x1c, 0x9b, 0x78, 0xa7, 0x2e, 0x58, 0x45, 0x1b, 0xba, 0xf3, 0xfb, 0x62, 0x87, 0x97, 0xf8, 0x96}} return a, nil } @@ -157,7 +157,7 @@ func ConfigCliFleetEthTestJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "../config/cli/fleet-eth.test.json", size: 2315, mode: os.FileMode(0644), modTime: time.Unix(1614163663, 0)} + info := bindataFileInfo{name: "../config/cli/fleet-eth.test.json", size: 2315, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7, 0x92, 0x14, 0x26, 0xa6, 0x12, 0xb1, 0x0, 0x2d, 0xbe, 0x9a, 0xb7, 0x55, 0xdb, 0xfc, 0x1f, 0x75, 0xe, 0xc2, 0x2b, 0xad, 0xfe, 0x44, 0x78, 0x2e, 0x7f, 0x8, 0x7f, 0xd1, 0x9e, 0x11, 0x2c}} return a, nil } @@ -177,7 +177,7 @@ func ConfigCliLesEnabledJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "../config/cli/les-enabled.json", size: 58, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "../config/cli/les-enabled.json", size: 58, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7e, 0xee, 0x27, 0xa7, 0x74, 0xa0, 0x46, 0xa1, 0x41, 0xed, 0x4d, 0x16, 0x5b, 0xf3, 0xf0, 0x7c, 0xc8, 0x2f, 0x6f, 0x47, 0xa4, 0xbb, 0x5f, 0x43, 0x33, 0xd, 0x9, 0x9d, 0xea, 0x9e, 0x15, 0xee}} return a, nil } @@ -197,7 +197,7 @@ func ConfigCliMailserverEnabledJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "../config/cli/mailserver-enabled.json", size: 176, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "../config/cli/mailserver-enabled.json", size: 176, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0xec, 0x81, 0x8b, 0x99, 0xb6, 0xdb, 0xc0, 0x8b, 0x46, 0x97, 0x96, 0xc7, 0x58, 0x30, 0x33, 0xef, 0x54, 0x25, 0x87, 0x7b, 0xb9, 0x94, 0x6b, 0x18, 0xa4, 0x5b, 0x58, 0x67, 0x7c, 0x44, 0xa6}} return a, nil } @@ -217,7 +217,7 @@ func ConfigStatusChainGenesisJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "../config/status-chain-genesis.json", size: 612, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "../config/status-chain-genesis.json", size: 612, mode: os.FileMode(0644), modTime: time.Unix(1599559876, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb, 0xf0, 0xc, 0x1, 0x95, 0x65, 0x6, 0x55, 0x48, 0x8f, 0x83, 0xa0, 0xb4, 0x81, 0xda, 0xad, 0x30, 0x6d, 0xb2, 0x78, 0x1b, 0x26, 0x4, 0x13, 0x12, 0x9, 0x6, 0xae, 0x3a, 0x2c, 0x1, 0x71}} return a, nil } @@ -237,7 +237,7 @@ func keysBootnodeKey() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "keys/bootnode.key", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "keys/bootnode.key", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x31, 0xcf, 0x27, 0xd4, 0x96, 0x2e, 0x32, 0xcd, 0x58, 0x96, 0x2a, 0xe5, 0x8c, 0xa0, 0xf1, 0x73, 0x1f, 0xd6, 0xd6, 0x8b, 0xb, 0x73, 0xd3, 0x2c, 0x84, 0x1a, 0x56, 0xa4, 0x74, 0xb6, 0x95, 0x20}} return a, nil } @@ -257,7 +257,7 @@ func keysFirebaseauthkey() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "keys/firebaseauthkey", size: 153, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "keys/firebaseauthkey", size: 153, mode: os.FileMode(0644), modTime: time.Unix(1536843582, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe, 0x69, 0x23, 0x64, 0x7d, 0xf9, 0x14, 0x37, 0x6f, 0x2b, 0x1, 0xf0, 0xb0, 0xa4, 0xb2, 0xd0, 0x18, 0xcd, 0xf9, 0xeb, 0x57, 0xa3, 0xfd, 0x79, 0x25, 0xa7, 0x9c, 0x3, 0xce, 0x26, 0xec, 0xe1}} return a, nil } @@ -277,7 +277,7 @@ func keysTestAccount1StatusChainPk() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "keys/test-account1-status-chain.pk", size: 489, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "keys/test-account1-status-chain.pk", size: 489, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8f, 0xba, 0x35, 0x1, 0x2b, 0x9d, 0xad, 0xf0, 0x2d, 0x3c, 0x4d, 0x6, 0xb5, 0x22, 0x2, 0x47, 0xd4, 0x1c, 0xf4, 0x31, 0x2f, 0xb, 0x5b, 0x27, 0x5d, 0x43, 0x97, 0x58, 0x2d, 0xf0, 0xe1, 0xbe}} return a, nil } @@ -297,7 +297,7 @@ func keysTestAccount1Pk() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "keys/test-account1.pk", size: 491, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "keys/test-account1.pk", size: 491, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9, 0x43, 0xc2, 0xf4, 0x8c, 0xc6, 0x64, 0x25, 0x8c, 0x7, 0x8c, 0xa8, 0x89, 0x2b, 0x7b, 0x9b, 0x4f, 0x81, 0xcb, 0xce, 0x3d, 0xef, 0x82, 0x9c, 0x27, 0x27, 0xa9, 0xc5, 0x46, 0x70, 0x30, 0x38}} return a, nil } @@ -317,7 +317,7 @@ func keysTestAccount2StatusChainPk() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "keys/test-account2-status-chain.pk", size: 489, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "keys/test-account2-status-chain.pk", size: 489, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9, 0xf8, 0x5c, 0xe9, 0x92, 0x96, 0x2d, 0x88, 0x2b, 0x8e, 0x42, 0x3f, 0xa4, 0x93, 0x6c, 0xad, 0xe9, 0xc0, 0x1b, 0x8a, 0x8, 0x8c, 0x5e, 0x7a, 0x84, 0xa2, 0xf, 0x9f, 0x77, 0x58, 0x2c, 0x2c}} return a, nil } @@ -337,7 +337,7 @@ func keysTestAccount2Pk() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "keys/test-account2.pk", size: 491, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "keys/test-account2.pk", size: 491, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9f, 0x72, 0xd5, 0x95, 0x5c, 0x5a, 0x99, 0x9d, 0x2f, 0x21, 0x83, 0xd7, 0x10, 0x17, 0x4a, 0x3d, 0x65, 0xc9, 0x26, 0x1a, 0x2c, 0x9d, 0x65, 0x63, 0xd2, 0xa0, 0xfc, 0x7c, 0x0, 0x87, 0x38, 0x9f}} return a, nil } @@ -357,7 +357,7 @@ func keysTestAccount3BeforeEip55Pk() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "keys/test-account3-before-eip55.pk", size: 489, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "keys/test-account3-before-eip55.pk", size: 489, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x81, 0x40, 0x56, 0xc1, 0x5e, 0x10, 0x6e, 0x28, 0x15, 0x3, 0x4e, 0xc4, 0xc4, 0x71, 0x4d, 0x16, 0x99, 0xcc, 0x1b, 0x63, 0xee, 0x10, 0x20, 0xe4, 0x59, 0x52, 0x3f, 0xc0, 0xad, 0x15, 0x13, 0x72}} return a, nil } diff --git a/t/bindata.go b/t/bindata.go index 8f1eaca53..14abbfc1e 100644 --- a/t/bindata.go +++ b/t/bindata.go @@ -86,7 +86,7 @@ func configPublicChainAccountsJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "config/public-chain-accounts.json", size: 307, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "config/public-chain-accounts.json", size: 307, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x76, 0x5d, 0xc0, 0xfe, 0x57, 0x50, 0x18, 0xec, 0x2d, 0x61, 0x1b, 0xa9, 0x81, 0x11, 0x5f, 0x77, 0xf7, 0xb6, 0x67, 0x82, 0x1, 0x40, 0x68, 0x9d, 0xc5, 0x41, 0xaf, 0xce, 0x43, 0x81, 0x92, 0x96}} return a, nil } @@ -106,7 +106,7 @@ func configStatusChainAccountsJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "config/status-chain-accounts.json", size: 543, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "config/status-chain-accounts.json", size: 543, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8e, 0xb3, 0x61, 0x51, 0x70, 0x3c, 0x12, 0x3e, 0xf1, 0x1c, 0x81, 0xfb, 0x9a, 0x7c, 0xe3, 0x63, 0xd0, 0x8f, 0x12, 0xc5, 0x2d, 0xf4, 0xea, 0x27, 0x33, 0xef, 0xca, 0xf9, 0x3f, 0x72, 0x44, 0xbf}} return a, nil } @@ -126,7 +126,7 @@ func configTestDataJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "config/test-data.json", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1588844135, 0)} + info := bindataFileInfo{name: "config/test-data.json", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1599559877, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xce, 0x9d, 0x80, 0xf5, 0x87, 0xfa, 0x57, 0x1d, 0xa1, 0xd5, 0x7a, 0x10, 0x3, 0xac, 0xd7, 0xf4, 0x64, 0x32, 0x96, 0x2b, 0xb7, 0x21, 0xb7, 0xa6, 0x80, 0x40, 0xe9, 0x65, 0xe3, 0xd6, 0xbd, 0x40}} return a, nil }