Tests and linting
This commit is contained in:
parent
093dda687f
commit
d9ea6a910e
|
@ -35,7 +35,6 @@
|
||||||
// 0019_blocks_ranges_extra_data.up.sql (89B)
|
// 0019_blocks_ranges_extra_data.up.sql (89B)
|
||||||
// 0020_metrics.up.sql (235B)
|
// 0020_metrics.up.sql (235B)
|
||||||
// 0021_add_session_id_to_metrics.up.sql (55B)
|
// 0021_add_session_id_to_metrics.up.sql (55B)
|
||||||
// 0021_profile_pictures_show_to_up.sql (81B)
|
|
||||||
// 0022_pending_transfers.up.sql (706B)
|
// 0022_pending_transfers.up.sql (706B)
|
||||||
// 1618237885_settings_anon_metrics_should_send.up.sql (80B)
|
// 1618237885_settings_anon_metrics_should_send.up.sql (80B)
|
||||||
// 1618395756_contacts_only.up.sql (136B)
|
// 1618395756_contacts_only.up.sql (136B)
|
||||||
|
@ -49,6 +48,7 @@
|
||||||
// 1630464455_create-saved_addresses-table.up.sql (187B)
|
// 1630464455_create-saved_addresses-table.up.sql (187B)
|
||||||
// 1630485153_networks.down.sql (21B)
|
// 1630485153_networks.down.sql (21B)
|
||||||
// 1630485153_networks.up.sql (394B)
|
// 1630485153_networks.up.sql (394B)
|
||||||
|
// 1632262444_profile_pictures_show_to.up.sql (81B)
|
||||||
// doc.go (74B)
|
// doc.go (74B)
|
||||||
|
|
||||||
package migrations
|
package migrations
|
||||||
|
@ -818,26 +818,6 @@ func _0021_add_session_id_to_metricsUpSql() (*asset, error) {
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var __0021_profile_pictures_show_to_upSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\x4e\x2d\x29\xc9\xcc\x4b\x2f\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x28\x28\xca\x4f\xcb\xcc\x49\x8d\x2f\xc8\x4c\x2e\x29\x2d\x4a\x2d\x8e\x2f\xce\xc8\x2f\x8f\x2f\xc9\x57\xf0\xf4\x0b\x51\xf0\xf3\x0f\x51\xf0\x0b\xf5\xf1\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x30\xb4\xe6\x02\x04\x00\x00\xff\xff\x2f\x7a\xa3\xb9\x51\x00\x00\x00")
|
|
||||||
|
|
||||||
func _0021_profile_pictures_show_to_upSqlBytes() ([]byte, error) {
|
|
||||||
return bindataRead(
|
|
||||||
__0021_profile_pictures_show_to_upSql,
|
|
||||||
"0021_profile_pictures_show_to_up.sql",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _0021_profile_pictures_show_to_upSql() (*asset, error) {
|
|
||||||
bytes, err := _0021_profile_pictures_show_to_upSqlBytes()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
info := bindataFileInfo{name: "0021_profile_pictures_show_to_up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1628512648, 0)}
|
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc3, 0xa2, 0x5a, 0x94, 0xde, 0x86, 0x2a, 0x29, 0xf5, 0xb3, 0x36, 0xe7, 0x53, 0x81, 0x55, 0xc9, 0xb5, 0xc3, 0xf4, 0x8c, 0x65, 0x2c, 0x4c, 0x48, 0xfd, 0x3c, 0xb7, 0x14, 0xb4, 0xea, 0x7a, 0x13}}
|
|
||||||
return a, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var __0022_pending_transfersUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x92\x4f\x6f\xe2\x30\x10\xc5\xef\xfe\x14\x73\x04\xc9\x87\xbd\x73\x72\xc0\x80\xb5\xc1\x46\xce\xb0\xc0\xc9\xf2\xe2\x14\xac\xe6\x9f\x62\xb7\x15\xdf\xbe\x22\xb4\x25\x50\x8a\x7a\x7d\xcf\xf3\x7b\xa3\xe7\x61\x29\x72\x0d\xc8\x92\x94\x43\x93\x57\xce\x57\x7b\x13\x5b\x5b\x05\xbb\x8b\xbe\xae\x02\x68\x2e\xd9\x82\x03\xaa\xbb\xb6\xa9\x0b\x37\x22\x64\xac\x39\x43\xfe\x81\x11\x53\x90\x0a\x81\x6f\x44\x86\xd9\x7d\xe8\x80\x00\x54\x79\x7c\xab\xdb\x67\xe3\x1d\xac\x64\x26\x66\x92\x4f\x20\x11\x33\x21\xb1\x1b\x97\xab\x34\xa5\x04\xe0\x60\xc3\x01\xfe\x31\x3d\x9e\x33\x7d\x65\x44\x5f\xe6\x21\xda\xb2\x79\x38\xfe\xd4\xd6\xa5\xb1\xce\xb5\x79\x08\xf7\x31\xf5\xad\x7d\x52\xc3\xb1\xfc\x5f\x17\x7d\x65\x6f\x83\x69\x5a\xbf\xcb\x21\x49\x55\xf2\xa9\x14\xbe\xf4\xf1\x4b\x79\xb5\xc5\xcb\xc5\x77\x36\x5a\x40\xbe\xc1\x2e\xe6\xd8\xe4\x7d\x9c\x75\xce\x9f\xba\xb0\x85\xb9\x7a\xb7\xd4\x62\xc1\xf4\x16\xfe\xf2\x2d\x0c\x2e\x15\xd1\xae\x87\x21\x19\xc2\x5a\xe0\x5c\xad\x10\xb4\x5a\x8b\xc9\x88\x10\x21\x33\xae\x11\x84\xfc\xe1\x87\xbe\x41\xe8\x55\x27\xb4\x57\x00\xed\xb6\xa4\xb7\xbb\xd1\x4b\xd5\x43\x92\xf1\x94\x8f\x11\xfa\xd0\x5e\x9a\xf9\x5d\xc0\x99\xfa\x07\xa6\x5a\x2d\x1e\x9d\xd5\x44\xab\xe5\x83\xdb\x3c\xbf\x7a\x0f\x00\x00\xff\xff\x05\xa2\xfe\xa8\xc2\x02\x00\x00")
|
var __0022_pending_transfersUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x92\x4f\x6f\xe2\x30\x10\xc5\xef\xfe\x14\x73\x04\xc9\x87\xbd\x73\x72\xc0\x80\xb5\xc1\x46\xce\xb0\xc0\xc9\xf2\xe2\x14\xac\xe6\x9f\x62\xb7\x15\xdf\xbe\x22\xb4\x25\x50\x8a\x7a\x7d\xcf\xf3\x7b\xa3\xe7\x61\x29\x72\x0d\xc8\x92\x94\x43\x93\x57\xce\x57\x7b\x13\x5b\x5b\x05\xbb\x8b\xbe\xae\x02\x68\x2e\xd9\x82\x03\xaa\xbb\xb6\xa9\x0b\x37\x22\x64\xac\x39\x43\xfe\x81\x11\x53\x90\x0a\x81\x6f\x44\x86\xd9\x7d\xe8\x80\x00\x54\x79\x7c\xab\xdb\x67\xe3\x1d\xac\x64\x26\x66\x92\x4f\x20\x11\x33\x21\xb1\x1b\x97\xab\x34\xa5\x04\xe0\x60\xc3\x01\xfe\x31\x3d\x9e\x33\x7d\x65\x44\x5f\xe6\x21\xda\xb2\x79\x38\xfe\xd4\xd6\xa5\xb1\xce\xb5\x79\x08\xf7\x31\xf5\xad\x7d\x52\xc3\xb1\xfc\x5f\x17\x7d\x65\x6f\x83\x69\x5a\xbf\xcb\x21\x49\x55\xf2\xa9\x14\xbe\xf4\xf1\x4b\x79\xb5\xc5\xcb\xc5\x77\x36\x5a\x40\xbe\xc1\x2e\xe6\xd8\xe4\x7d\x9c\x75\xce\x9f\xba\xb0\x85\xb9\x7a\xb7\xd4\x62\xc1\xf4\x16\xfe\xf2\x2d\x0c\x2e\x15\xd1\xae\x87\x21\x19\xc2\x5a\xe0\x5c\xad\x10\xb4\x5a\x8b\xc9\x88\x10\x21\x33\xae\x11\x84\xfc\xe1\x87\xbe\x41\xe8\x55\x27\xb4\x57\x00\xed\xb6\xa4\xb7\xbb\xd1\x4b\xd5\x43\x92\xf1\x94\x8f\x11\xfa\xd0\x5e\x9a\xf9\x5d\xc0\x99\xfa\x07\xa6\x5a\x2d\x1e\x9d\xd5\x44\xab\xe5\x83\xdb\x3c\xbf\x7a\x0f\x00\x00\xff\xff\x05\xa2\xfe\xa8\xc2\x02\x00\x00")
|
||||||
|
|
||||||
func _0022_pending_transfersUpSqlBytes() ([]byte, error) {
|
func _0022_pending_transfersUpSqlBytes() ([]byte, error) {
|
||||||
|
@ -1098,6 +1078,26 @@ func _1630485153_networksUpSql() (*asset, error) {
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var __1632262444_profile_pictures_show_toUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\x4e\x2d\x29\xc9\xcc\x4b\x2f\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x28\x28\xca\x4f\xcb\xcc\x49\x8d\x2f\xc8\x4c\x2e\x29\x2d\x4a\x2d\x8e\x2f\xce\xc8\x2f\x8f\x2f\xc9\x57\xf0\xf4\x0b\x51\xf0\xf3\x0f\x51\xf0\x0b\xf5\xf1\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x30\xb4\xe6\x02\x04\x00\x00\xff\xff\x2f\x7a\xa3\xb9\x51\x00\x00\x00")
|
||||||
|
|
||||||
|
func _1632262444_profile_pictures_show_toUpSqlBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
__1632262444_profile_pictures_show_toUpSql,
|
||||||
|
"1632262444_profile_pictures_show_to.up.sql",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _1632262444_profile_pictures_show_toUpSql() (*asset, error) {
|
||||||
|
bytes, err := _1632262444_profile_pictures_show_toUpSqlBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{name: "1632262444_profile_pictures_show_to.up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1632518530, 0)}
|
||||||
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc3, 0xa2, 0x5a, 0x94, 0xde, 0x86, 0x2a, 0x29, 0xf5, 0xb3, 0x36, 0xe7, 0x53, 0x81, 0x55, 0xc9, 0xb5, 0xc3, 0xf4, 0x8c, 0x65, 0x2c, 0x4c, 0x48, 0xfd, 0x3c, 0xb7, 0x14, 0xb4, 0xea, 0x7a, 0x13}}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00")
|
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00")
|
||||||
|
|
||||||
func docGoBytes() ([]byte, error) {
|
func docGoBytes() ([]byte, error) {
|
||||||
|
@ -1279,8 +1279,6 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
|
|
||||||
"0021_add_session_id_to_metrics.up.sql": _0021_add_session_id_to_metricsUpSql,
|
"0021_add_session_id_to_metrics.up.sql": _0021_add_session_id_to_metricsUpSql,
|
||||||
|
|
||||||
"0021_profile_pictures_show_to_up.sql": _0021_profile_pictures_show_to_upSql,
|
|
||||||
|
|
||||||
"0022_pending_transfers.up.sql": _0022_pending_transfersUpSql,
|
"0022_pending_transfers.up.sql": _0022_pending_transfersUpSql,
|
||||||
|
|
||||||
"1618237885_settings_anon_metrics_should_send.up.sql": _1618237885_settings_anon_metrics_should_sendUpSql,
|
"1618237885_settings_anon_metrics_should_send.up.sql": _1618237885_settings_anon_metrics_should_sendUpSql,
|
||||||
|
@ -1307,6 +1305,8 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
|
|
||||||
"1630485153_networks.up.sql": _1630485153_networksUpSql,
|
"1630485153_networks.up.sql": _1630485153_networksUpSql,
|
||||||
|
|
||||||
|
"1632262444_profile_pictures_show_to.up.sql": _1632262444_profile_pictures_show_toUpSql,
|
||||||
|
|
||||||
"doc.go": docGo,
|
"doc.go": docGo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1386,7 +1386,6 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
||||||
"0019_blocks_ranges_extra_data.up.sql": &bintree{_0019_blocks_ranges_extra_dataUpSql, map[string]*bintree{}},
|
"0019_blocks_ranges_extra_data.up.sql": &bintree{_0019_blocks_ranges_extra_dataUpSql, map[string]*bintree{}},
|
||||||
"0020_metrics.up.sql": &bintree{_0020_metricsUpSql, map[string]*bintree{}},
|
"0020_metrics.up.sql": &bintree{_0020_metricsUpSql, map[string]*bintree{}},
|
||||||
"0021_add_session_id_to_metrics.up.sql": &bintree{_0021_add_session_id_to_metricsUpSql, map[string]*bintree{}},
|
"0021_add_session_id_to_metrics.up.sql": &bintree{_0021_add_session_id_to_metricsUpSql, map[string]*bintree{}},
|
||||||
"0021_profile_pictures_show_to_up.sql": &bintree{_0021_profile_pictures_show_to_upSql, map[string]*bintree{}},
|
|
||||||
"0022_pending_transfers.up.sql": &bintree{_0022_pending_transfersUpSql, map[string]*bintree{}},
|
"0022_pending_transfers.up.sql": &bintree{_0022_pending_transfersUpSql, map[string]*bintree{}},
|
||||||
"1618237885_settings_anon_metrics_should_send.up.sql": &bintree{_1618237885_settings_anon_metrics_should_sendUpSql, map[string]*bintree{}},
|
"1618237885_settings_anon_metrics_should_send.up.sql": &bintree{_1618237885_settings_anon_metrics_should_sendUpSql, map[string]*bintree{}},
|
||||||
"1618395756_contacts_only.up.sql": &bintree{_1618395756_contacts_onlyUpSql, map[string]*bintree{}},
|
"1618395756_contacts_only.up.sql": &bintree{_1618395756_contacts_onlyUpSql, map[string]*bintree{}},
|
||||||
|
@ -1400,7 +1399,8 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
||||||
"1630464455_create-saved_addresses-table.up.sql": &bintree{_1630464455_createSaved_addressesTableUpSql, map[string]*bintree{}},
|
"1630464455_create-saved_addresses-table.up.sql": &bintree{_1630464455_createSaved_addressesTableUpSql, map[string]*bintree{}},
|
||||||
"1630485153_networks.down.sql": &bintree{_1630485153_networksDownSql, map[string]*bintree{}},
|
"1630485153_networks.down.sql": &bintree{_1630485153_networksDownSql, map[string]*bintree{}},
|
||||||
"1630485153_networks.up.sql": &bintree{_1630485153_networksUpSql, map[string]*bintree{}},
|
"1630485153_networks.up.sql": &bintree{_1630485153_networksUpSql, map[string]*bintree{}},
|
||||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
"1632262444_profile_pictures_show_to.up.sql": &bintree{_1632262444_profile_pictures_show_toUpSql, map[string]*bintree{}},
|
||||||
|
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// RestoreAsset restores an asset under the given directory.
|
// RestoreAsset restores an asset under the given directory.
|
||||||
|
|
|
@ -15,14 +15,18 @@ const (
|
||||||
uniqueWalletConstraint = "UNIQUE constraint failed: accounts.wallet"
|
uniqueWalletConstraint = "UNIQUE constraint failed: accounts.wallet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ProfilePicturesVisibilityType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProfilePicturesVisibilityContactsOnly = iota + 1
|
ProfilePicturesVisibilityContactsOnly ProfilePicturesVisibilityType = iota + 1
|
||||||
ProfilePicturesVisibilityEveryone
|
ProfilePicturesVisibilityEveryone
|
||||||
ProfilePicturesVisibilityNone
|
ProfilePicturesVisibilityNone
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ProfilePicturesShowToType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProfilePicturesShowToContactsOnly = iota + 1
|
ProfilePicturesShowToContactsOnly ProfilePicturesShowToType = iota + 1
|
||||||
ProfilePicturesShowToEveryone
|
ProfilePicturesShowToEveryone
|
||||||
ProfilePicturesShowToNone
|
ProfilePicturesShowToNone
|
||||||
)
|
)
|
||||||
|
@ -117,21 +121,21 @@ type Settings struct {
|
||||||
SendPushNotifications bool `json:"send-push-notifications?,omitempty"`
|
SendPushNotifications bool `json:"send-push-notifications?,omitempty"`
|
||||||
Appearance uint `json:"appearance"`
|
Appearance uint `json:"appearance"`
|
||||||
// ProfilePicturesShowTo indicates to whom the user shows their profile picture to (contacts, everyone)
|
// ProfilePicturesShowTo indicates to whom the user shows their profile picture to (contacts, everyone)
|
||||||
ProfilePicturesShowTo uint `json:"profile-pictures-show-to"`
|
ProfilePicturesShowTo ProfilePicturesShowToType `json:"profile-pictures-show-to"`
|
||||||
// ProfilePicturesVisibility indicates who we want to see profile pictures of (contacts, everyone or none)
|
// ProfilePicturesVisibility indicates who we want to see profile pictures of (contacts, everyone or none)
|
||||||
ProfilePicturesVisibility uint `json:"profile-pictures-visibility"`
|
ProfilePicturesVisibility ProfilePicturesVisibilityType `json:"profile-pictures-visibility"`
|
||||||
UseMailservers bool `json:"use-mailservers?"`
|
UseMailservers bool `json:"use-mailservers?"`
|
||||||
Usernames *json.RawMessage `json:"usernames,omitempty"`
|
Usernames *json.RawMessage `json:"usernames,omitempty"`
|
||||||
WalletRootAddress types.Address `json:"wallet-root-address,omitempty"`
|
WalletRootAddress types.Address `json:"wallet-root-address,omitempty"`
|
||||||
WalletSetUpPassed bool `json:"wallet-set-up-passed?,omitempty"`
|
WalletSetUpPassed bool `json:"wallet-set-up-passed?,omitempty"`
|
||||||
WalletVisibleTokens *json.RawMessage `json:"wallet/visible-tokens,omitempty"`
|
WalletVisibleTokens *json.RawMessage `json:"wallet/visible-tokens,omitempty"`
|
||||||
WakuBloomFilterMode bool `json:"waku-bloom-filter-mode,omitempty"`
|
WakuBloomFilterMode bool `json:"waku-bloom-filter-mode,omitempty"`
|
||||||
WebViewAllowPermissionRequests bool `json:"webview-allow-permission-requests?,omitempty"`
|
WebViewAllowPermissionRequests bool `json:"webview-allow-permission-requests?,omitempty"`
|
||||||
SendStatusUpdates bool `json:"send-status-updates?,omitempty"`
|
SendStatusUpdates bool `json:"send-status-updates?,omitempty"`
|
||||||
CurrentUserStatus *json.RawMessage `json:"current-user-status"`
|
CurrentUserStatus *json.RawMessage `json:"current-user-status"`
|
||||||
GifRecents *json.RawMessage `json:"gifs/recent-gifs"`
|
GifRecents *json.RawMessage `json:"gifs/recent-gifs"`
|
||||||
GifFavorites *json.RawMessage `json:"gifs/favorite-gifs"`
|
GifFavorites *json.RawMessage `json:"gifs/favorite-gifs"`
|
||||||
OpenseaEnabled bool `json:"opensea-enabled?,omitempty"`
|
OpenseaEnabled bool `json:"opensea-enabled?,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDB(db *sql.DB) *Database {
|
func NewDB(db *sql.DB) *Database {
|
||||||
|
|
|
@ -36,6 +36,7 @@ var (
|
||||||
PublicKey: "0x04211fe0f69772ecf7eb0b5bfc7678672508a9fb01f2d699096f0d59ef7fe1a0cb1e648a80190db1c0f5f088872444d846f2956d0bd84069f3f9f69335af852ac0",
|
PublicKey: "0x04211fe0f69772ecf7eb0b5bfc7678672508a9fb01f2d699096f0d59ef7fe1a0cb1e648a80190db1c0f5f088872444d846f2956d0bd84069f3f9f69335af852ac0",
|
||||||
SigningPhrase: "yurt joey vibe",
|
SigningPhrase: "yurt joey vibe",
|
||||||
SendPushNotifications: true,
|
SendPushNotifications: true,
|
||||||
|
ProfilePicturesShowTo: ProfilePicturesShowToContactsOnly,
|
||||||
ProfilePicturesVisibility: ProfilePicturesVisibilityContactsOnly,
|
ProfilePicturesVisibility: ProfilePicturesVisibilityContactsOnly,
|
||||||
DefaultSyncPeriod: 86400,
|
DefaultSyncPeriod: 86400,
|
||||||
UseMailservers: true,
|
UseMailservers: true,
|
||||||
|
|
|
@ -15,10 +15,10 @@ import (
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const(
|
const (
|
||||||
nonceLength = 12
|
nonceLength = 12
|
||||||
defaultECHDSharedKeyLength = 16
|
defaultECHDSharedKeyLength = 16
|
||||||
defaultECHDMACLength = 16
|
defaultECHDMACLength = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrInvalidCiphertextLength = errors.New("invalid cyphertext length")
|
var ErrInvalidCiphertextLength = errors.New("invalid cyphertext length")
|
||||||
|
|
|
@ -9,17 +9,18 @@ import (
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
)
|
)
|
||||||
|
|
||||||
func EncryptIdentityImagesWithContactPubKeys(iis map[string]*protobuf.IdentityImage, m *Messenger) error {
|
func EncryptIdentityImagesWithContactPubKeys(iis map[string]*protobuf.IdentityImage, m *Messenger) (err error) {
|
||||||
// Make AES key
|
// Make AES key
|
||||||
AESKey := make([]byte, 32)
|
AESKey := make([]byte, 32)
|
||||||
_, err := crand.Read(AESKey)
|
_, err = crand.Read(AESKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ii := range iis {
|
for _, ii := range iis {
|
||||||
// Encrypt image payload with the AES key
|
// Encrypt image payload with the AES key
|
||||||
encryptedPayload, err := common.Encrypt(ii.Payload, AESKey, crand.Reader)
|
var encryptedPayload []byte
|
||||||
|
encryptedPayload, err = common.Encrypt(ii.Payload, AESKey, crand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -27,29 +28,36 @@ func EncryptIdentityImagesWithContactPubKeys(iis map[string]*protobuf.IdentityIm
|
||||||
// Overwrite the unencrypted payload with the newly encrypted payload
|
// Overwrite the unencrypted payload with the newly encrypted payload
|
||||||
ii.Payload = encryptedPayload
|
ii.Payload = encryptedPayload
|
||||||
ii.Encrypted = true
|
ii.Encrypted = true
|
||||||
for _, c := range m.allContacts {
|
m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
|
||||||
if !c.IsAdded() {
|
if !contact.IsAdded() {
|
||||||
continue
|
return true
|
||||||
}
|
}
|
||||||
|
var pubK *ecdsa.PublicKey
|
||||||
|
var sharedKey []byte
|
||||||
|
var eAESKey []byte
|
||||||
|
|
||||||
pubK, err := c.PublicKey()
|
pubK, err = contact.PublicKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false
|
||||||
}
|
}
|
||||||
// Generate a Diffie-Helman (DH) between the sender private key and the recipient's public key
|
// Generate a Diffie-Helman (DH) between the sender private key and the recipient's public key
|
||||||
sharedKey, err := common.MakeECDHSharedKey(m.identity, pubK)
|
sharedKey, err = common.MakeECDHSharedKey(m.identity, pubK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt the main AES key with AES encryption using the DH key
|
// Encrypt the main AES key with AES encryption using the DH key
|
||||||
eAESKey, err := common.Encrypt(AESKey, sharedKey, crand.Reader)
|
eAESKey, err = common.Encrypt(AESKey, sharedKey, crand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the the encrypted main AES key to the IdentityImage's EncryptionKeys slice.
|
// Append the the encrypted main AES key to the IdentityImage's EncryptionKeys slice.
|
||||||
ii.EncryptionKeys = append(ii.EncryptionKeys, eAESKey)
|
ii.EncryptionKeys = append(ii.EncryptionKeys, eAESKey)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +82,7 @@ image:
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if dAESKey == nil{
|
if dAESKey == nil {
|
||||||
return errors.New("decrypting the payload encryption key resulted in no error and a nil key")
|
return errors.New("decrypting the payload encryption key resulted in no error and a nil key")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,4 +105,3 @@ image:
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -612,11 +612,18 @@ func (m *Messenger) publishContactCode() error {
|
||||||
if contactCodeAdvertisement == nil {
|
if contactCodeAdvertisement == nil {
|
||||||
contactCodeAdvertisement = &protobuf.ContactCodeAdvertisement{}
|
contactCodeAdvertisement = &protobuf.ContactCodeAdvertisement{}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.attachChatIdentity(contactCodeAdvertisement)
|
err = m.attachChatIdentity(contactCodeAdvertisement)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if contactCodeAdvertisement.ChatIdentity != nil {
|
||||||
|
m.logger.Debug("attached chat identity", zap.Int("images len", len(contactCodeAdvertisement.ChatIdentity.Images)))
|
||||||
|
} else {
|
||||||
|
m.logger.Debug("no attached chat identity")
|
||||||
|
}
|
||||||
|
|
||||||
payload, err = proto.Marshal(contactCodeAdvertisement)
|
payload, err = proto.Marshal(contactCodeAdvertisement)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -634,6 +641,7 @@ func (m *Messenger) publishContactCode() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.logger.Warn("failed to send a contact code", zap.Error(err))
|
m.logger.Warn("failed to send a contact code", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
m.logger.Debug("contact code sent")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,7 +649,9 @@ func (m *Messenger) publishContactCode() error {
|
||||||
// if the `shouldPublish` conditions are met
|
// if the `shouldPublish` conditions are met
|
||||||
func (m *Messenger) attachChatIdentity(cca *protobuf.ContactCodeAdvertisement) error {
|
func (m *Messenger) attachChatIdentity(cca *protobuf.ContactCodeAdvertisement) error {
|
||||||
contactCodeTopic := transport.ContactCodeTopic(&m.identity.PublicKey)
|
contactCodeTopic := transport.ContactCodeTopic(&m.identity.PublicKey)
|
||||||
|
|
||||||
shouldPublish, err := m.shouldPublishChatIdentity(contactCodeTopic)
|
shouldPublish, err := m.shouldPublishChatIdentity(contactCodeTopic)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -747,6 +757,7 @@ func (m *Messenger) shouldPublishChatIdentity(chatID string) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: If Alice does not add bob as a contact she will not update her contact code with images
|
||||||
return lp == 0 || time.Now().Unix()-lp > 24*60*60, nil
|
return lp == 0 || time.Now().Unix()-lp > 24*60*60, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,12 +795,6 @@ func (m *Messenger) attachIdentityImagesToChatIdentity(context chatContext, ci *
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.ProfilePicturesVisibility == accounts.ProfilePicturesVisibilityContactsOnly {
|
|
||||||
m.logger.Info("settings.ProfilePicturesVisibility is there")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO check that all the migration code is in place use ProfilePicturesVisibility as a guide
|
|
||||||
// getting an error of no such column: profile_pictures_show_to
|
|
||||||
if s.ProfilePicturesShowTo == accounts.ProfilePicturesShowToNone {
|
if s.ProfilePicturesShowTo == accounts.ProfilePicturesShowToNone {
|
||||||
m.logger.Info(fmt.Sprintf("settings.ProfilePicturesShowTo is set to '%d', skipping attaching IdentityImages", s.ProfilePicturesShowTo))
|
m.logger.Info(fmt.Sprintf("settings.ProfilePicturesShowTo is set to '%d', skipping attaching IdentityImages", s.ProfilePicturesShowTo))
|
||||||
return nil
|
return nil
|
||||||
|
@ -2907,6 +2912,7 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
||||||
logger.Debug("Received ContactCodeAdvertisement")
|
logger.Debug("Received ContactCodeAdvertisement")
|
||||||
|
|
||||||
cca := msg.ParsedMessage.Interface().(protobuf.ContactCodeAdvertisement)
|
cca := msg.ParsedMessage.Interface().(protobuf.ContactCodeAdvertisement)
|
||||||
|
logger.Debug("protobuf.ContactCodeAdvertisement received", zap.Any("cca", cca))
|
||||||
if cca.ChatIdentity != nil {
|
if cca.ChatIdentity != nil {
|
||||||
|
|
||||||
logger.Debug("Received ContactCodeAdvertisement ChatIdentity")
|
logger.Debug("Received ContactCodeAdvertisement ChatIdentity")
|
||||||
|
|
|
@ -2,11 +2,14 @@ package protocol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/status-im/status-go/appdatabase/migrations"
|
"github.com/status-im/status-go/appdatabase/migrations"
|
||||||
"github.com/status-im/status-go/multiaccounts"
|
"github.com/status-im/status-go/multiaccounts"
|
||||||
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/protocol/anonmetrics"
|
"github.com/status-im/status-go/protocol/anonmetrics"
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/communities"
|
"github.com/status-im/status-go/protocol/communities"
|
||||||
|
@ -113,6 +116,25 @@ func WithToplevelDatabaseMigrations() Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithAppSettings(s accounts.Settings, nc params.NodeConfig) Option {
|
||||||
|
return func(c *config) error {
|
||||||
|
c.afterDbCreatedHooks = append(c.afterDbCreatedHooks, func(c *config) error {
|
||||||
|
if s.Networks == nil {
|
||||||
|
networks := new(json.RawMessage)
|
||||||
|
if err := networks.UnmarshalJSON([]byte("net")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Networks = networks
|
||||||
|
}
|
||||||
|
|
||||||
|
sDB := accounts.NewDB(c.db)
|
||||||
|
return sDB.CreateSettings(s, nc)
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WithMultiAccounts(ma *multiaccounts.Database) Option {
|
func WithMultiAccounts(ma *multiaccounts.Database) Option {
|
||||||
return func(c *config) error {
|
return func(c *config) error {
|
||||||
c.multiAccount = ma
|
c.multiAccount = ma
|
||||||
|
|
|
@ -5,9 +5,11 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
|
"github.com/status-im/status-go/protocol/transport"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *Messenger) SaveContact(contact *Contact) error {
|
func (m *Messenger) SaveContact(contact *Contact) error {
|
||||||
|
@ -48,6 +50,15 @@ func (m *Messenger) AddContact(ctx context.Context, pubKey string) (*MessengerRe
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset last published time for ChatIdentity so new contact can receive data
|
||||||
|
contactCodeTopic := transport.ContactCodeTopic(&m.identity.PublicKey)
|
||||||
|
m.logger.Debug("contact state changed ResetWhenChatIdentityLastPublished")
|
||||||
|
err = m.persistence.ResetWhenChatIdentityLastPublished(contactCodeTopic)
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Error("ResetWhenChatIdentityLastPublished error", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Create the corresponding chat
|
// Create the corresponding chat
|
||||||
profileChat := m.buildProfileChat(contact.ID)
|
profileChat := m.buildProfileChat(contact.ID)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
"github.com/status-im/status-go/images"
|
"github.com/status-im/status-go/images"
|
||||||
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/communities"
|
"github.com/status-im/status-go/protocol/communities"
|
||||||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||||
|
@ -1309,18 +1310,41 @@ func (m *Messenger) HandleGroupChatInvitation(state *ReceivedMessageState, pbGHI
|
||||||
// HandleChatIdentity handles an incoming protobuf.ChatIdentity
|
// HandleChatIdentity handles an incoming protobuf.ChatIdentity
|
||||||
// extracts contact information stored in the protobuf and adds it to the user's contact for update.
|
// extracts contact information stored in the protobuf and adds it to the user's contact for update.
|
||||||
func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci protobuf.ChatIdentity) error {
|
func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci protobuf.ChatIdentity) error {
|
||||||
logger := m.logger.With(zap.String("site", "HandleChatIdentity"))
|
s, err := m.settings.GetSettings()
|
||||||
allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !allowed {
|
viewFromContacts := s.ProfilePicturesVisibility == accounts.ProfilePicturesVisibilityContactsOnly
|
||||||
return ErrMessageNotAllowed
|
viewFromNoOne := s.ProfilePicturesVisibility == accounts.ProfilePicturesVisibilityNone
|
||||||
|
|
||||||
|
m.logger.Debug("settings found",
|
||||||
|
zap.Bool("viewFromContacts", viewFromContacts),
|
||||||
|
zap.Bool("viewFromNoOne", viewFromNoOne),
|
||||||
|
)
|
||||||
|
|
||||||
|
// If we don't want to view profile images from anyone, don't process identity images.
|
||||||
|
// We don't want to store the profile images of other users, even if we don't display images.
|
||||||
|
if viewFromNoOne {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no images attached to a ChatIdentity, check if message is allowed
|
||||||
|
// Or if there are images and visibility is set to from contacts only, check if message is allowed
|
||||||
|
// otherwise process the images without checking if the message is allowed
|
||||||
|
if len(ci.Images) == 0 || (len(ci.Images) > 0 && (viewFromContacts)) {
|
||||||
|
allowed, err := m.isMessageAllowedFrom(state.CurrentMessageState.Contact.ID, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allowed {
|
||||||
|
return ErrMessageNotAllowed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
contact := state.CurrentMessageState.Contact
|
contact := state.CurrentMessageState.Contact
|
||||||
|
|
||||||
err := DecryptIdentityImagesWithIdentityPrivateKey(ci.Images, m.identity, state.CurrentMessageState.PublicKey)
|
err = DecryptIdentityImagesWithIdentityPrivateKey(ci.Images, m.identity, state.CurrentMessageState.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1332,7 +1356,6 @@ func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci protobuf.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("Handling contact update")
|
|
||||||
newImages, err := m.persistence.SaveContactChatIdentity(contact.ID, &ci)
|
newImages, err := m.persistence.SaveContactChatIdentity(contact.ID, &ci)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -0,0 +1,519 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cenkalti/backoff/v3"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
||||||
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/images"
|
||||||
|
"github.com/status-im/status-go/multiaccounts"
|
||||||
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
|
"github.com/status-im/status-go/protocol/tt"
|
||||||
|
"github.com/status-im/status-go/waku"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMessengerProfilePictureHandlerSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(MessengerProfilePictureHandlerSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessengerProfilePictureHandlerSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
alice *Messenger // client instance of Messenger
|
||||||
|
bob *Messenger // server instance of Messenger
|
||||||
|
|
||||||
|
aliceKey *ecdsa.PrivateKey // private key for the alice instance of Messenger
|
||||||
|
bobKey *ecdsa.PrivateKey // private key for the bob instance of Messenger
|
||||||
|
|
||||||
|
// If one wants to send messages between different instances of Messenger,
|
||||||
|
// a single Waku service should be shared.
|
||||||
|
shh types.Waku
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) SetupSuite() {
|
||||||
|
s.logger = tt.MustCreateTestLogger()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) setup() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Setup Waku things
|
||||||
|
config := waku.DefaultConfig
|
||||||
|
config.MinimumAcceptedPoW = 0
|
||||||
|
wakuLogger := s.logger.Named("Waku")
|
||||||
|
shh := waku.New(&config, wakuLogger)
|
||||||
|
s.shh = gethbridge.NewGethWakuWrapper(shh)
|
||||||
|
s.Require().NoError(shh.Start())
|
||||||
|
|
||||||
|
// Generate private keys for Alice and Bob
|
||||||
|
s.aliceKey, err = crypto.GenerateKey()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.bobKey, err = crypto.GenerateKey()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
// Generate Alice Messenger
|
||||||
|
aliceLogger := s.logger.Named("Alice messenger")
|
||||||
|
s.alice, err = newMessengerWithKey(s.shh, s.aliceKey, aliceLogger, []Option{})
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("alice messenger created")
|
||||||
|
|
||||||
|
// Generate Bob Messenger
|
||||||
|
bobLogger := s.logger.Named("Bob messenger")
|
||||||
|
s.bob, err = newMessengerWithKey(s.shh, s.bobKey, bobLogger, []Option{})
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("bob messenger created")
|
||||||
|
|
||||||
|
// Setup MultiAccount for Alice Messenger
|
||||||
|
s.logger.Debug("alice setupMultiAccount before")
|
||||||
|
s.setupMultiAccount(s.alice)
|
||||||
|
s.logger.Debug("alice setupMultiAccount after")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) setupTest() {
|
||||||
|
s.logger.Debug("setupTest fired")
|
||||||
|
s.setup()
|
||||||
|
s.logger.Debug("setupTest completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) SetupTest() {
|
||||||
|
s.logger.Debug("SetupTest fired")
|
||||||
|
s.setup()
|
||||||
|
s.logger.Debug("SetupTest completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) tearDown() {
|
||||||
|
// Shutdown messengers
|
||||||
|
s.NoError(s.alice.Shutdown())
|
||||||
|
s.alice = nil
|
||||||
|
s.NoError(s.bob.Shutdown())
|
||||||
|
s.bob = nil
|
||||||
|
_ = s.logger.Sync()
|
||||||
|
//time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) tearDownTest() {
|
||||||
|
s.logger.Debug("tearDownTest fired")
|
||||||
|
s.tearDown()
|
||||||
|
s.logger.Debug("tearDownTest completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) TearDownTest() {
|
||||||
|
s.logger.Debug("TearDownTest fired")
|
||||||
|
s.tearDown()
|
||||||
|
s.logger.Debug("TearDownTest completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) generateKeyUID(publicKey *ecdsa.PublicKey) string {
|
||||||
|
return types.EncodeHex(crypto.FromECDSAPub(publicKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) setupMultiAccount(m *Messenger) {
|
||||||
|
keyUID := s.generateKeyUID(&m.identity.PublicKey)
|
||||||
|
m.account = &multiaccounts.Account{KeyUID: keyUID}
|
||||||
|
|
||||||
|
err := m.multiAccounts.SaveAccount(multiaccounts.Account{Name: "string", KeyUID: keyUID})
|
||||||
|
s.NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) generateAndStoreIdentityImages(m *Messenger) []*images.IdentityImage {
|
||||||
|
keyUID := s.generateKeyUID(&m.identity.PublicKey)
|
||||||
|
iis := images.SampleIdentityImages()
|
||||||
|
s.Require().NoError(m.multiAccounts.StoreIdentityImages(keyUID, iis))
|
||||||
|
|
||||||
|
return iis
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) TestChatIdentity() {
|
||||||
|
iis := s.generateAndStoreIdentityImages(s.alice)
|
||||||
|
ci, err := s.alice.createChatIdentity(privateChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Exactly(len(iis), len(ci.Images))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) TestEncryptDecryptIdentityImagesWithContactPubKeys() {
|
||||||
|
smPayload := "hello small image"
|
||||||
|
lgPayload := "hello large image"
|
||||||
|
|
||||||
|
ci := protobuf.ChatIdentity{
|
||||||
|
Clock: uint64(time.Now().Unix()),
|
||||||
|
Images: map[string]*protobuf.IdentityImage{
|
||||||
|
"small": {
|
||||||
|
Payload: []byte(smPayload),
|
||||||
|
},
|
||||||
|
"large": {
|
||||||
|
Payload: []byte(lgPayload),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make contact keys and Contacts, set the Contacts to added
|
||||||
|
contactKeys := make([]*ecdsa.PrivateKey, 10)
|
||||||
|
for i := range contactKeys {
|
||||||
|
contactKey, err := crypto.GenerateKey()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
contactKeys[i] = contactKey
|
||||||
|
|
||||||
|
contact, err := BuildContactFromPublicKey(&contactKey.PublicKey)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
contact.SystemTags = append(contact.SystemTags, contactAdded)
|
||||||
|
s.alice.allContacts.Store(contact.ID, contact)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test EncryptIdentityImagesWithContactPubKeys
|
||||||
|
err := EncryptIdentityImagesWithContactPubKeys(ci.Images, s.alice)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
for _, ii := range ci.Images {
|
||||||
|
s.Require().Equal(s.alice.allContacts.Len(), len(ii.EncryptionKeys))
|
||||||
|
}
|
||||||
|
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
|
||||||
|
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
|
||||||
|
s.Require().True(ci.Images["small"].Encrypted)
|
||||||
|
s.Require().True(ci.Images["large"].Encrypted)
|
||||||
|
|
||||||
|
// Test DecryptIdentityImagesWithIdentityPrivateKey
|
||||||
|
err = DecryptIdentityImagesWithIdentityPrivateKey(ci.Images, contactKeys[2], &s.alice.identity.PublicKey)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
s.Require().Equal(smPayload, string(ci.Images["small"].Payload))
|
||||||
|
s.Require().Equal(lgPayload, string(ci.Images["large"].Payload))
|
||||||
|
s.Require().False(ci.Images["small"].Encrypted)
|
||||||
|
s.Require().False(ci.Images["large"].Encrypted)
|
||||||
|
|
||||||
|
// RESET Messenger identity, Contacts and IdentityImage.EncryptionKeys
|
||||||
|
s.alice.allContacts = new(contactMap)
|
||||||
|
ci.Images["small"].EncryptionKeys = nil
|
||||||
|
ci.Images["large"].EncryptionKeys = nil
|
||||||
|
|
||||||
|
// Test EncryptIdentityImagesWithContactPubKeys with no contacts
|
||||||
|
err = EncryptIdentityImagesWithContactPubKeys(ci.Images, s.alice)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
for _, ii := range ci.Images {
|
||||||
|
s.Require().Equal(0, len(ii.EncryptionKeys))
|
||||||
|
}
|
||||||
|
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
|
||||||
|
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
|
||||||
|
s.Require().True(ci.Images["small"].Encrypted)
|
||||||
|
s.Require().True(ci.Images["large"].Encrypted)
|
||||||
|
|
||||||
|
// Test DecryptIdentityImagesWithIdentityPrivateKey with no valid identity
|
||||||
|
err = DecryptIdentityImagesWithIdentityPrivateKey(ci.Images, contactKeys[2], &s.alice.identity.PublicKey)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
|
||||||
|
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
|
||||||
|
s.Require().True(ci.Images["small"].Encrypted)
|
||||||
|
s.Require().True(ci.Images["large"].Encrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerProfilePictureHandlerSuite) TestE2eSendingReceivingProfilePicture() {
|
||||||
|
profilePicShowSettings := map[string]accounts.ProfilePicturesShowToType{
|
||||||
|
"ShowToContactsOnly": accounts.ProfilePicturesShowToContactsOnly,
|
||||||
|
"ShowToEveryone": accounts.ProfilePicturesShowToEveryone,
|
||||||
|
"ShowToNone": accounts.ProfilePicturesShowToNone,
|
||||||
|
}
|
||||||
|
|
||||||
|
profilePicViewSettings := map[string]accounts.ProfilePicturesVisibilityType{
|
||||||
|
"ViewFromContactsOnly": accounts.ProfilePicturesVisibilityContactsOnly,
|
||||||
|
"ViewFromEveryone": accounts.ProfilePicturesVisibilityEveryone,
|
||||||
|
"ViewFromNone": accounts.ProfilePicturesVisibilityNone,
|
||||||
|
}
|
||||||
|
|
||||||
|
isContactFor := map[string][]bool{
|
||||||
|
"alice": {true, false},
|
||||||
|
"bob": {true, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
chatContexts := []chatContext{
|
||||||
|
publicChat,
|
||||||
|
privateChat,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO see if possible to push each test scenario into a go routine
|
||||||
|
for _, cc := range chatContexts {
|
||||||
|
for sn, ss := range profilePicShowSettings {
|
||||||
|
for vn, vs := range profilePicViewSettings {
|
||||||
|
for _, ac := range isContactFor["alice"] {
|
||||||
|
for _, bc := range isContactFor["bob"] {
|
||||||
|
s.logger.Debug("top of the loop")
|
||||||
|
s.setupTest()
|
||||||
|
s.logger.Info("testing with criteria:",
|
||||||
|
zap.String("chat context type", string(cc)),
|
||||||
|
zap.String("profile picture Show Settings", sn),
|
||||||
|
zap.String("profile picture View Settings", vn),
|
||||||
|
zap.Bool("bob in Alice's Contacts", ac),
|
||||||
|
zap.Bool("alice in Bob's Contacts", bc),
|
||||||
|
)
|
||||||
|
|
||||||
|
expectPicture, err := resultExpected(ss, vs, ac, bc)
|
||||||
|
s.logger.Debug("expect to receive a profile pic?",
|
||||||
|
zap.Bool("result", expectPicture),
|
||||||
|
zap.Error(err))
|
||||||
|
|
||||||
|
// Setting up Bob
|
||||||
|
s.logger.Debug("Setting up test criteria for Bob")
|
||||||
|
|
||||||
|
s.logger.Debug("Save bob profile-pictures-visibility setting before")
|
||||||
|
err = s.bob.settings.SaveSetting("profile-pictures-visibility", vs)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("Save bob profile-pictures-visibility setting after")
|
||||||
|
|
||||||
|
s.logger.Debug("bob add contact before")
|
||||||
|
if bc {
|
||||||
|
s.logger.Debug("bob has contact to add")
|
||||||
|
_, err = s.bob.AddContact(context.Background(), s.generateKeyUID(&s.alice.identity.PublicKey))
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("bob add contact after")
|
||||||
|
}
|
||||||
|
s.logger.Debug("bob add contact after after")
|
||||||
|
|
||||||
|
// Create Bob's chats
|
||||||
|
switch cc {
|
||||||
|
case publicChat:
|
||||||
|
s.logger.Debug("making publicChats for bob")
|
||||||
|
|
||||||
|
// Bob opens up the public chat and joins it
|
||||||
|
bChat := CreatePublicChat("status", s.alice.transport)
|
||||||
|
err = s.bob.SaveChat(bChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
_, err = s.bob.Join(bChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
case privateChat:
|
||||||
|
s.logger.Debug("making privateChats for bob")
|
||||||
|
|
||||||
|
s.logger.Debug("Bob making one to one chat with alice")
|
||||||
|
bChat := CreateOneToOneChat(s.generateKeyUID(&s.aliceKey.PublicKey), &s.aliceKey.PublicKey, s.alice.transport)
|
||||||
|
s.logger.Debug("Bob saving one to one chat with alice")
|
||||||
|
err = s.bob.SaveChat(bChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("Bob saved one to one chat with alice")
|
||||||
|
|
||||||
|
s.logger.Debug("Bob joining one to one chat with alice")
|
||||||
|
_, err = s.bob.Join(bChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("Bob joined one to one chat with alice")
|
||||||
|
default:
|
||||||
|
s.Failf("unexpected chat context type", "%s", string(cc))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting up Alice
|
||||||
|
s.logger.Debug("Setting up test criteria for Alice")
|
||||||
|
|
||||||
|
s.logger.Debug("Save alice profile-pictures-show-to setting before")
|
||||||
|
err = s.alice.settings.SaveSetting("profile-pictures-show-to", ss)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("Save alice profile-pictures-show-to setting after")
|
||||||
|
|
||||||
|
s.logger.Debug("alice add contact before")
|
||||||
|
if ac {
|
||||||
|
s.logger.Debug("alice has contact to add")
|
||||||
|
_, err = s.alice.AddContact(context.Background(), s.generateKeyUID(&s.bob.identity.PublicKey))
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("alice add contact after")
|
||||||
|
}
|
||||||
|
s.logger.Debug("alice add contact after after")
|
||||||
|
|
||||||
|
s.logger.Debug("generateAndStoreIdentityImages before")
|
||||||
|
iis := s.generateAndStoreIdentityImages(s.alice)
|
||||||
|
s.logger.Debug("generateAndStoreIdentityImages after")
|
||||||
|
|
||||||
|
s.logger.Debug("Before making chat for alice")
|
||||||
|
// Create chats
|
||||||
|
var aChat *Chat
|
||||||
|
switch cc {
|
||||||
|
case publicChat:
|
||||||
|
s.logger.Debug("making publicChats for alice")
|
||||||
|
|
||||||
|
// Alice opens creates a public chat
|
||||||
|
aChat = CreatePublicChat("status", s.alice.transport)
|
||||||
|
err = s.alice.SaveChat(aChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
case privateChat:
|
||||||
|
s.logger.Debug("making privateChats for alice")
|
||||||
|
|
||||||
|
s.logger.Debug("Alice making one to one chat with bob")
|
||||||
|
aChat = CreateOneToOneChat(s.generateKeyUID(&s.bobKey.PublicKey), &s.bobKey.PublicKey, s.bob.transport)
|
||||||
|
s.logger.Debug("Alice saving one to one chat with bob")
|
||||||
|
err = s.alice.SaveChat(aChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("Alice saved one to one chat with bob")
|
||||||
|
|
||||||
|
s.logger.Debug("Alice joining one to one chat with bob")
|
||||||
|
_, err = s.alice.Join(aChat)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.logger.Debug("Alice joined one to one chat with bob")
|
||||||
|
|
||||||
|
s.logger.Debug("alice before manually triggering publishContactCode")
|
||||||
|
err = s.alice.publishContactCode()
|
||||||
|
s.logger.Debug("alice after manually triggering publishContactCode",
|
||||||
|
zap.Error(err))
|
||||||
|
s.Require().NoError(err)
|
||||||
|
default:
|
||||||
|
s.Failf("unexpected chat context type", "%s", string(cc))
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Debug("Build and send a chat from alice")
|
||||||
|
|
||||||
|
// Alice sends a message to the public chat
|
||||||
|
message := buildTestMessage(*aChat)
|
||||||
|
response, err := s.alice.SendChatMessage(context.Background(), message)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
|
||||||
|
// Poll bob to see if he got the chatIdentity
|
||||||
|
// Retrieve ChatIdentity
|
||||||
|
var contacts []*Contact
|
||||||
|
|
||||||
|
s.logger.Debug("Checking Bob to see if he got the chatIdentity")
|
||||||
|
options := func(b *backoff.ExponentialBackOff) {
|
||||||
|
b.MaxElapsedTime = 2 * time.Second
|
||||||
|
}
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
|
||||||
|
response, err = s.bob.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
contacts = response.Contacts
|
||||||
|
s.logger.Debug("RetryWithBackOff contact data", zap.Any("contacts", contacts))
|
||||||
|
|
||||||
|
if len(contacts) > 0 && len(contacts[0].Images) > 0 {
|
||||||
|
s.logger.Debug("", zap.Any("contacts", contacts))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("no new contacts with images received")
|
||||||
|
}, options)
|
||||||
|
|
||||||
|
s.logger.Debug("Finished RetryWithBackOff got Bob",
|
||||||
|
zap.Any("contacts", contacts),
|
||||||
|
zap.Error(err))
|
||||||
|
|
||||||
|
if expectPicture {
|
||||||
|
s.logger.Debug("expecting a contact with images")
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(contacts)
|
||||||
|
} else {
|
||||||
|
s.logger.Debug("expecting no contacts with images")
|
||||||
|
s.Require().EqualError(err, "no new contacts with images received")
|
||||||
|
s.logger.Info("Completed testing with criteria:",
|
||||||
|
zap.String("chat context type", string(cc)),
|
||||||
|
zap.String("profile picture Show Settings", sn),
|
||||||
|
zap.String("profile picture View Settings", vn),
|
||||||
|
zap.Bool("bob in Alice's Contacts", ac),
|
||||||
|
zap.Bool("alice in Bob's Contacts", bc),
|
||||||
|
)
|
||||||
|
s.tearDownTest()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Debug("checking alice's contact")
|
||||||
|
|
||||||
|
// Check if alice's contact data with profile picture is there
|
||||||
|
var contact *Contact
|
||||||
|
for _, c := range contacts {
|
||||||
|
if c.ID == s.generateKeyUID(&s.alice.identity.PublicKey) {
|
||||||
|
contact = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.Require().NotNil(contact)
|
||||||
|
|
||||||
|
s.logger.Debug("checked alice's contact info all good")
|
||||||
|
|
||||||
|
// Check that Bob now has Alice's profile picture(s)
|
||||||
|
switch cc {
|
||||||
|
case publicChat:
|
||||||
|
// In public chat context we only need the images.SmallDimName, but also may have the large
|
||||||
|
s.Require().GreaterOrEqual(len(contact.Images), 1)
|
||||||
|
|
||||||
|
// Check if the result matches expectation
|
||||||
|
smImg, ok := contact.Images[images.SmallDimName]
|
||||||
|
s.Require().True(ok, "contact images must contain the images.SmallDimName")
|
||||||
|
|
||||||
|
for _, ii := range iis {
|
||||||
|
if ii.Name == images.SmallDimName {
|
||||||
|
s.Require().Equal(ii.Payload, smImg.Payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case privateChat:
|
||||||
|
s.Require().Equal(len(contact.Images), 2)
|
||||||
|
s.logger.Info("private chat chat images", zap.Any("iis", iis))
|
||||||
|
|
||||||
|
// Check if the result matches expectation
|
||||||
|
smImg, ok := contact.Images[images.SmallDimName]
|
||||||
|
s.Require().True(ok, "contact images must contain the images.SmallDimName")
|
||||||
|
|
||||||
|
lgImg, ok := contact.Images[images.LargeDimName]
|
||||||
|
s.Require().True(ok, "contact images must contain the images.LargeDimName")
|
||||||
|
|
||||||
|
for _, ii := range iis {
|
||||||
|
switch ii.Name {
|
||||||
|
case images.SmallDimName:
|
||||||
|
s.Require().Equal(ii.Payload, smImg.Payload)
|
||||||
|
case images.LargeDimName:
|
||||||
|
s.Require().Equal(ii.Payload, lgImg.Payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info("Completed testing with criteria:",
|
||||||
|
zap.String("chat context type", string(cc)),
|
||||||
|
zap.String("profile picture Show Settings", sn),
|
||||||
|
zap.String("profile picture View Settings", vn),
|
||||||
|
zap.Bool("bob in Alice's Contacts", ac),
|
||||||
|
zap.Bool("alice in Bob's Contacts", bc),
|
||||||
|
)
|
||||||
|
s.tearDownTest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.setupTest()
|
||||||
|
}
|
||||||
|
|
||||||
|
func resultExpected(ss accounts.ProfilePicturesShowToType, vs accounts.ProfilePicturesVisibilityType, ac, bc bool) (bool, error) {
|
||||||
|
switch ss {
|
||||||
|
case accounts.ProfilePicturesShowToContactsOnly:
|
||||||
|
if ac {
|
||||||
|
return resultExpectedVS(vs, bc)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
case accounts.ProfilePicturesShowToEveryone:
|
||||||
|
return resultExpectedVS(vs, bc)
|
||||||
|
case accounts.ProfilePicturesShowToNone:
|
||||||
|
return false, nil
|
||||||
|
default:
|
||||||
|
return false, errors.New("unknown ProfilePicturesShowToType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resultExpectedVS(vs accounts.ProfilePicturesVisibilityType, bc bool) (bool, error) {
|
||||||
|
switch vs {
|
||||||
|
case accounts.ProfilePicturesVisibilityContactsOnly:
|
||||||
|
return true, nil
|
||||||
|
case accounts.ProfilePicturesVisibilityEveryone:
|
||||||
|
return true, nil
|
||||||
|
case accounts.ProfilePicturesVisibilityNone:
|
||||||
|
return false, nil
|
||||||
|
default:
|
||||||
|
return false, errors.New("unknown ProfilePicturesVisibilityType")
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,7 +81,7 @@ func (cm *contactMap) Delete(contactID string) {
|
||||||
|
|
||||||
func (cm *contactMap) Len() int {
|
func (cm *contactMap) Len() int {
|
||||||
count := 0
|
count := 0
|
||||||
cm.Range(func(key string, value *Contact) (shouldContinue bool) {
|
cm.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
|
||||||
count++
|
count++
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
_ "github.com/mutecomm/go-sqlcipher" // require go-sqlcipher that overrides default implementation
|
_ "github.com/mutecomm/go-sqlcipher" // require go-sqlcipher that overrides default implementation
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
@ -24,11 +23,11 @@ import (
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
enstypes "github.com/status-im/status-go/eth-node/types/ens"
|
enstypes "github.com/status-im/status-go/eth-node/types/ens"
|
||||||
"github.com/status-im/status-go/images"
|
|
||||||
"github.com/status-im/status-go/multiaccounts"
|
"github.com/status-im/status-go/multiaccounts"
|
||||||
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
"github.com/status-im/status-go/protocol/requests"
|
|
||||||
"github.com/status-im/status-go/protocol/tt"
|
"github.com/status-im/status-go/protocol/tt"
|
||||||
v1protocol "github.com/status-im/status-go/protocol/v1"
|
v1protocol "github.com/status-im/status-go/protocol/v1"
|
||||||
"github.com/status-im/status-go/waku"
|
"github.com/status-im/status-go/waku"
|
||||||
|
@ -133,6 +132,7 @@ func newMessengerWithKey(shh types.Waku, privateKey *ecdsa.PrivateKey, logger *z
|
||||||
WithAccount(iai.ToMultiAccount()),
|
WithAccount(iai.ToMultiAccount()),
|
||||||
WithDatasync(),
|
WithDatasync(),
|
||||||
WithToplevelDatabaseMigrations(),
|
WithToplevelDatabaseMigrations(),
|
||||||
|
WithAppSettings(accounts.Settings{}, params.NodeConfig{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
options = append(options, extraOptions...)
|
options = append(options, extraOptions...)
|
||||||
|
@ -2489,157 +2489,3 @@ func WaitOnMessengerResponse(m *Messenger, condition func(*MessengerResponse) bo
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerSuite) TestChatIdentity() {
|
|
||||||
keyUID := "0xdeadbeef"
|
|
||||||
s.m.account = &multiaccounts.Account{KeyUID: keyUID}
|
|
||||||
|
|
||||||
err := s.m.multiAccounts.SaveAccount(multiaccounts.Account{Name: "string", KeyUID: keyUID})
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
iis := images.SampleIdentityImages()
|
|
||||||
s.Require().NoError(s.m.multiAccounts.StoreIdentityImages(keyUID, iis))
|
|
||||||
|
|
||||||
ci, err := s.m.createChatIdentity("private-chat")
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
s.Require().Exactly(len(iis), len(ci.Images))
|
|
||||||
|
|
||||||
spew.Dump(ci, len(ci.Images))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MessengerSuite) TestPublicMessageOnCommunityChat() {
|
|
||||||
alice := s.newMessenger(s.shh)
|
|
||||||
bob := s.newMessenger(s.shh)
|
|
||||||
|
|
||||||
// Create a community
|
|
||||||
description := &requests.CreateCommunity{
|
|
||||||
Membership: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
|
||||||
Name: "status",
|
|
||||||
Color: "#ffffff",
|
|
||||||
Description: "status community description",
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := bob.CreateCommunity(description)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
s.Require().NotNil(response)
|
|
||||||
s.Require().Len(response.Communities(), 1)
|
|
||||||
community := response.Communities()[0]
|
|
||||||
|
|
||||||
// Create a community chat
|
|
||||||
response, err = bob.CreateCommunityChat(community.ID(), &protobuf.CommunityChat{
|
|
||||||
Permissions: &protobuf.CommunityPermissions{
|
|
||||||
Access: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
|
||||||
},
|
|
||||||
Identity: &protobuf.ChatIdentity{
|
|
||||||
DisplayName: "community-name",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
s.Require().NoError(err)
|
|
||||||
s.Require().NotNil(response)
|
|
||||||
s.Require().Len(response.Chats(), 1)
|
|
||||||
chat := response.Chats()[0]
|
|
||||||
|
|
||||||
inputMessage := buildTestMessage(*chat)
|
|
||||||
inputMessage.ID = "1"
|
|
||||||
inputMessage.Seen = false
|
|
||||||
inputMessage.Text = "hey @" + common.PubkeyToHex(&s.m.identity.PublicKey)
|
|
||||||
inputMessage.Mentioned = true
|
|
||||||
inputMessage.MessageType = protobuf.MessageType_PUBLIC_GROUP
|
|
||||||
|
|
||||||
contact, err := BuildContactFromPublicKey(&alice.identity.PublicKey)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
// send a public chat message to a community on_request chat
|
|
||||||
state := &ReceivedMessageState{
|
|
||||||
Response: &MessengerResponse{},
|
|
||||||
CurrentMessageState: &CurrentMessageState{
|
|
||||||
Message: inputMessage.ChatMessage,
|
|
||||||
MessageID: "0xabc",
|
|
||||||
WhisperTimestamp: s.m.getTimesource().GetCurrentTime(),
|
|
||||||
Contact: contact,
|
|
||||||
PublicKey: &alice.identity.PublicKey,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = bob.HandleChatMessage(state)
|
|
||||||
s.Require().Error(err)
|
|
||||||
s.Require().Equal(ErrMessageForWrongChatType, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *MessengerSuite) TestEncryptDecryptIdentityImagesWithContactPubKeys() {
|
|
||||||
smPayload := "hello small image"
|
|
||||||
lgPayload := "hello large image"
|
|
||||||
|
|
||||||
ci := protobuf.ChatIdentity{
|
|
||||||
Clock: uint64(time.Now().Unix()),
|
|
||||||
Images: map[string]*protobuf.IdentityImage{
|
|
||||||
"small": {
|
|
||||||
Payload: []byte(smPayload),
|
|
||||||
},
|
|
||||||
"large": {
|
|
||||||
Payload: []byte(lgPayload),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make contact keys and Contacts, set the Contacts to added
|
|
||||||
contactKeys := make([]*ecdsa.PrivateKey, 10)
|
|
||||||
for i := range contactKeys {
|
|
||||||
contactKey, err := crypto.GenerateKey()
|
|
||||||
s.Require().NoError(err)
|
|
||||||
contactKeys[i] = contactKey
|
|
||||||
|
|
||||||
contact, err := BuildContactFromPublicKey(&contactKey.PublicKey)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
contact.SystemTags = append(contact.SystemTags, contactAdded)
|
|
||||||
s.m.allContacts.Store(contact.ID, contact)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test EncryptIdentityImagesWithContactPubKeys
|
|
||||||
err := EncryptIdentityImagesWithContactPubKeys(ci.Images, s.m)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
for _, ii := range ci.Images {
|
|
||||||
s.Require().Equal(s.m.allContacts.Len, len(ii.EncryptionKeys))
|
|
||||||
}
|
|
||||||
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
|
|
||||||
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
|
|
||||||
s.Require().True(ci.Images["small"].Encrypted)
|
|
||||||
s.Require().True(ci.Images["large"].Encrypted)
|
|
||||||
|
|
||||||
// Test DecryptIdentityImagesWithIdentityPrivateKey
|
|
||||||
err = DecryptIdentityImagesWithIdentityPrivateKey(ci.Images, contactKeys[2], &s.m.identity.PublicKey)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
s.Require().Equal(smPayload, string(ci.Images["small"].Payload))
|
|
||||||
s.Require().Equal(lgPayload, string(ci.Images["large"].Payload))
|
|
||||||
s.Require().False(ci.Images["small"].Encrypted)
|
|
||||||
s.Require().False(ci.Images["large"].Encrypted)
|
|
||||||
|
|
||||||
// RESET Messenger identity, Contacts and IdentityImage.EncryptionKeys
|
|
||||||
s.m.allContacts = nil
|
|
||||||
ci.Images["small"].EncryptionKeys = nil
|
|
||||||
ci.Images["large"].EncryptionKeys = nil
|
|
||||||
|
|
||||||
// Test EncryptIdentityImagesWithContactPubKeys with no contacts
|
|
||||||
err = EncryptIdentityImagesWithContactPubKeys(ci.Images, s.m)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
for _, ii := range ci.Images {
|
|
||||||
s.Require().Equal(0, len(ii.EncryptionKeys))
|
|
||||||
}
|
|
||||||
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
|
|
||||||
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
|
|
||||||
s.Require().True(ci.Images["small"].Encrypted)
|
|
||||||
s.Require().True(ci.Images["large"].Encrypted)
|
|
||||||
|
|
||||||
// Test DecryptIdentityImagesWithIdentityPrivateKey with no valid identity
|
|
||||||
err = DecryptIdentityImagesWithIdentityPrivateKey(ci.Images, contactKeys[2], &s.m.identity.PublicKey)
|
|
||||||
s.Require().NoError(err)
|
|
||||||
|
|
||||||
s.Require().NotEqual([]byte(smPayload), ci.Images["small"].Payload)
|
|
||||||
s.Require().NotEqual([]byte(lgPayload), ci.Images["large"].Payload)
|
|
||||||
s.Require().True(ci.Images["small"].Encrypted)
|
|
||||||
s.Require().True(ci.Images["large"].Encrypted)
|
|
||||||
}
|
|
||||||
|
|
|
@ -590,6 +590,7 @@ func (db sqlitePersistence) SaveContactChatIdentity(contactID string, chatIdenti
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO implement something that doesn't reject all images if a single image fails validation
|
||||||
// Validate image URI to make sure it's serializable
|
// Validate image URI to make sure it's serializable
|
||||||
_, err = images.GetPayloadDataURI(image.Payload)
|
_, err = images.GetPayloadDataURI(image.Payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -844,6 +845,34 @@ func (db sqlitePersistence) SaveWhenChatIdentityLastPublished(chatID string, has
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db sqlitePersistence) ResetWhenChatIdentityLastPublished(chatID string) (err error) {
|
||||||
|
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = tx.Commit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// don't shadow original error
|
||||||
|
_ = tx.Rollback()
|
||||||
|
}()
|
||||||
|
|
||||||
|
stmt, err := tx.Prepare("INSERT INTO chat_identity_last_published (chat_id, clock_value, hash) VALUES (?, ?, ?)")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
_, err = stmt.Exec(chatID, 0, []byte("."))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (db sqlitePersistence) InsertStatusUpdate(userStatus UserStatus) error {
|
func (db sqlitePersistence) InsertStatusUpdate(userStatus UserStatus) error {
|
||||||
_, err := db.db.Exec(`INSERT INTO status_updates(
|
_, err := db.db.Exec(`INSERT INTO status_updates(
|
||||||
public_key,
|
public_key,
|
||||||
|
|
|
@ -6,7 +6,9 @@ import (
|
||||||
"github.com/cenkalti/backoff/v3"
|
"github.com/cenkalti/backoff/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RetryWithBackOff(o func() error) error {
|
type BackOffOption func(*backoff.ExponentialBackOff)
|
||||||
|
|
||||||
|
func RetryWithBackOff(o func() error, options ...BackOffOption) error {
|
||||||
b := backoff.ExponentialBackOff{
|
b := backoff.ExponentialBackOff{
|
||||||
InitialInterval: time.Millisecond * 100,
|
InitialInterval: time.Millisecond * 100,
|
||||||
RandomizationFactor: 0.1,
|
RandomizationFactor: 0.1,
|
||||||
|
@ -15,6 +17,9 @@ func RetryWithBackOff(o func() error) error {
|
||||||
MaxElapsedTime: time.Second * 10,
|
MaxElapsedTime: time.Second * 10,
|
||||||
Clock: backoff.SystemClock,
|
Clock: backoff.SystemClock,
|
||||||
}
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
option(&b)
|
||||||
|
}
|
||||||
b.Reset()
|
b.Reset()
|
||||||
return backoff.Retry(o, &b)
|
return backoff.Retry(o, &b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,17 +86,8 @@ func _1565345162_initial_schemaDownSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD:vendor/github.com/vacp2p/mvds/node/migrations/migrations.go
|
|
||||||
info := bindataFileInfo{name: "1565345162_initial_schema.down.sql", size: 23, mode: os.FileMode(0644), modTime: time.Unix(1565345447, 0)}
|
info := bindataFileInfo{name: "1565345162_initial_schema.down.sql", size: 23, mode: os.FileMode(0644), modTime: time.Unix(1565345447, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7c, 0x69, 0xd2, 0x3, 0xea, 0x82, 0x7c, 0xb3, 0x44, 0x6c, 0xef, 0x64, 0x2c, 0x99, 0x62, 0xa2, 0x8b, 0x6f, 0x96, 0x4f, 0x34, 0x41, 0x87, 0xd5, 0x4e, 0x3, 0x7f, 0x4a, 0xd1, 0x91, 0x9, 0x99}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7c, 0x69, 0xd2, 0x3, 0xea, 0x82, 0x7c, 0xb3, 0x44, 0x6c, 0xef, 0x64, 0x2c, 0x99, 0x62, 0xa2, 0x8b, 0x6f, 0x96, 0x4f, 0x34, 0x41, 0x87, 0xd5, 0x4e, 0x3, 0x7f, 0x4a, 0xd1, 0x91, 0x9, 0x99}}
|
||||||
=======
|
|
||||||
<<<<<<< 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(1618493571, 0)}
|
|
||||||
>>>>>>> Added new Settings field ProfilePicturesShowTo
|
|
||||||
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}}
|
|
||||||
>>>>>>> Added new Settings field ProfilePicturesShowTo:protocol/transport/whisper/migrations/migrations.go
|
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,17 +106,8 @@ func _1565345162_initial_schemaUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD:vendor/github.com/vacp2p/mvds/node/migrations/migrations.go
|
|
||||||
info := bindataFileInfo{name: "1565345162_initial_schema.up.sql", size: 86, mode: os.FileMode(0644), modTime: time.Unix(1565345708, 0)}
|
info := bindataFileInfo{name: "1565345162_initial_schema.up.sql", size: 86, mode: os.FileMode(0644), modTime: time.Unix(1565345708, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x78, 0x7c, 0xdd, 0x67, 0x61, 0x3e, 0x7f, 0xd4, 0xce, 0xb0, 0x17, 0xbe, 0x5a, 0xa7, 0x9e, 0x93, 0x34, 0xe8, 0xbb, 0x44, 0xfb, 0x88, 0xd6, 0x18, 0x6d, 0x9f, 0xb4, 0x22, 0xda, 0xbc, 0x87, 0x94}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x78, 0x7c, 0xdd, 0x67, 0x61, 0x3e, 0x7f, 0xd4, 0xce, 0xb0, 0x17, 0xbe, 0x5a, 0xa7, 0x9e, 0x93, 0x34, 0xe8, 0xbb, 0x44, 0xfb, 0x88, 0xd6, 0x18, 0x6d, 0x9f, 0xb4, 0x22, 0xda, 0xbc, 0x87, 0x94}}
|
||||||
=======
|
|
||||||
<<<<<<< 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(1618493571, 0)}
|
|
||||||
>>>>>>> Added new Settings field ProfilePicturesShowTo
|
|
||||||
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}}
|
|
||||||
>>>>>>> Added new Settings field ProfilePicturesShowTo:protocol/transport/whisper/migrations/migrations.go
|
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,17 +126,8 @@ func docGo() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD:vendor/github.com/vacp2p/mvds/node/migrations/migrations.go
|
|
||||||
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1565345207, 0)}
|
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1565345207, 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}}
|
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}}
|
||||||
=======
|
|
||||||
<<<<<<< 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(1618493571, 0)}
|
|
||||||
>>>>>>> Added new Settings field ProfilePicturesShowTo
|
|
||||||
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}}
|
|
||||||
>>>>>>> Added new Settings field ProfilePicturesShowTo:protocol/transport/whisper/migrations/migrations.go
|
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue