Sync profile picture

This commit is contained in:
Vitaliy Vlasov 2022-03-24 11:35:56 +02:00 committed by Vitaliy Vlasov
parent 9de4eb3c8a
commit 16197dc807
19 changed files with 6013 additions and 259 deletions

View File

@ -15,6 +15,7 @@ type IdentityImage struct {
Height int Height int
FileSize int FileSize int
ResizeTarget int ResizeTarget int
Clock uint64
} }
func (i IdentityImage) GetType() (ImageType, error) { func (i IdentityImage) GetType() (ImageType, error) {
@ -48,6 +49,7 @@ func (i IdentityImage) MarshalJSON() ([]byte, error) {
Height int `json:"height"` Height int `json:"height"`
FileSize int `json:"fileSize"` FileSize int `json:"fileSize"`
ResizeTarget int `json:"resizeTarget"` ResizeTarget int `json:"resizeTarget"`
Clock uint64 `json:"clock"`
}{ }{
KeyUID: i.KeyUID, KeyUID: i.KeyUID,
Name: i.Name, Name: i.Name,
@ -56,6 +58,7 @@ func (i IdentityImage) MarshalJSON() ([]byte, error) {
Height: i.Height, Height: i.Height,
FileSize: i.FileSize, FileSize: i.FileSize,
ResizeTarget: i.ResizeTarget, ResizeTarget: i.ResizeTarget,
Clock: i.Clock,
} }
return json.Marshal(temp) return json.Marshal(temp)

View File

@ -63,7 +63,7 @@ func TestIdentityImage_MarshalJSON(t *testing.T) {
FileSize: 256, FileSize: 256,
ResizeTarget: 80, ResizeTarget: 80,
} }
expected := `{"keyUid":"","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80}` expected := `{"keyUid":"","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80,"clock":0}`
js, err := json.Marshal(ii) js, err := json.Marshal(ii)
require.NoError(t, err) require.NoError(t, err)

View File

@ -18,6 +18,7 @@ func SampleIdentityImages() []*IdentityImage {
Height: 80, Height: 80,
FileSize: 256, FileSize: 256,
ResizeTarget: 80, ResizeTarget: 80,
Clock: 0,
}, },
{ {
Name: LargeDimName, Name: LargeDimName,
@ -26,6 +27,7 @@ func SampleIdentityImages() []*IdentityImage {
Height: 300, Height: 300,
FileSize: 1024, FileSize: 1024,
ResizeTarget: 240, ResizeTarget: 240,
Clock: 0,
}, },
} }
} }

View File

@ -50,7 +50,7 @@ func (db *Database) Close() error {
} }
func (db *Database) GetAccounts() (rst []Account, err error) { func (db *Database) GetAccounts() (rst []Account, err error) {
rows, err := db.db.Query("SELECT a.name, a.loginTimestamp, a.identicon, a.colorHash, a.colorId, a.keycardPairing, a.keyUid, ii.name, ii.image_payload, ii.width, ii.height, ii.file_size, ii.resize_target FROM accounts AS a LEFT JOIN identity_images AS ii ON ii.key_uid = a.keyUid ORDER BY loginTimestamp DESC") rows, err := db.db.Query("SELECT a.name, a.loginTimestamp, a.identicon, a.colorHash, a.colorId, a.keycardPairing, a.keyUid, ii.name, ii.image_payload, ii.width, ii.height, ii.file_size, ii.resize_target, ii.clock FROM accounts AS a LEFT JOIN identity_images AS ii ON ii.key_uid = a.keyUid ORDER BY loginTimestamp DESC")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -71,6 +71,7 @@ func (db *Database) GetAccounts() (rst []Account, err error) {
iiHeight := sql.NullInt64{} iiHeight := sql.NullInt64{}
iiFileSize := sql.NullInt64{} iiFileSize := sql.NullInt64{}
iiResizeTarget := sql.NullInt64{} iiResizeTarget := sql.NullInt64{}
iiClock := sql.NullInt64{}
err = rows.Scan( err = rows.Scan(
&acc.Name, &acc.Name,
@ -86,6 +87,7 @@ func (db *Database) GetAccounts() (rst []Account, err error) {
&iiHeight, &iiHeight,
&iiFileSize, &iiFileSize,
&iiResizeTarget, &iiResizeTarget,
&iiClock,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -107,6 +109,7 @@ func (db *Database) GetAccounts() (rst []Account, err error) {
ii.Height = int(iiHeight.Int64) ii.Height = int(iiHeight.Int64)
ii.FileSize = int(iiFileSize.Int64) ii.FileSize = int(iiFileSize.Int64)
ii.ResizeTarget = int(iiResizeTarget.Int64) ii.ResizeTarget = int(iiResizeTarget.Int64)
ii.Clock = uint64(iiClock.Int64)
if ii.Name == "" && len(ii.Payload) == 0 && ii.Width == 0 && ii.Height == 0 && ii.FileSize == 0 && ii.ResizeTarget == 0 { if ii.Name == "" && len(ii.Payload) == 0 && ii.Width == 0 && ii.Height == 0 && ii.FileSize == 0 && ii.ResizeTarget == 0 {
ii = nil ii = nil
@ -171,7 +174,7 @@ func (db *Database) DeleteAccount(keyUID string) error {
// Account images // Account images
func (db *Database) GetIdentityImages(keyUID string) (iis []*images.IdentityImage, err error) { func (db *Database) GetIdentityImages(keyUID string) (iis []*images.IdentityImage, err error) {
rows, err := db.db.Query(`SELECT key_uid, name, image_payload, width, height, file_size, resize_target FROM identity_images WHERE key_uid = ?`, keyUID) rows, err := db.db.Query(`SELECT key_uid, name, image_payload, width, height, file_size, resize_target, clock FROM identity_images WHERE key_uid = ?`, keyUID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -182,7 +185,7 @@ func (db *Database) GetIdentityImages(keyUID string) (iis []*images.IdentityImag
for rows.Next() { for rows.Next() {
ii := &images.IdentityImage{} ii := &images.IdentityImage{}
err = rows.Scan(&ii.KeyUID, &ii.Name, &ii.Payload, &ii.Width, &ii.Height, &ii.FileSize, &ii.ResizeTarget) err = rows.Scan(&ii.KeyUID, &ii.Name, &ii.Payload, &ii.Width, &ii.Height, &ii.FileSize, &ii.ResizeTarget, &ii.Clock)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -195,7 +198,7 @@ func (db *Database) GetIdentityImages(keyUID string) (iis []*images.IdentityImag
func (db *Database) GetIdentityImage(keyUID, it string) (*images.IdentityImage, error) { func (db *Database) GetIdentityImage(keyUID, it string) (*images.IdentityImage, error) {
var ii images.IdentityImage var ii images.IdentityImage
err := db.db.QueryRow("SELECT key_uid, name, image_payload, width, height, file_size, resize_target FROM identity_images WHERE key_uid = ? AND name = ?", keyUID, it).Scan(&ii.KeyUID, &ii.Name, &ii.Payload, &ii.Width, &ii.Height, &ii.FileSize, &ii.ResizeTarget) err := db.db.QueryRow("SELECT key_uid, name, image_payload, width, height, file_size, resize_target, clock FROM identity_images WHERE key_uid = ? AND name = ?", keyUID, it).Scan(&ii.KeyUID, &ii.Name, &ii.Payload, &ii.Width, &ii.Height, &ii.FileSize, &ii.ResizeTarget, &ii.Clock)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, nil return nil, nil
} else if err != nil { } else if err != nil {
@ -204,7 +207,7 @@ func (db *Database) GetIdentityImage(keyUID, it string) (*images.IdentityImage,
return &ii, nil return &ii, nil
} }
func (db *Database) StoreIdentityImages(keyUID string, iis []*images.IdentityImage) (err error) { func (db *Database) StoreIdentityImages(keyUID string, iis []*images.IdentityImage, publish bool) (err error) {
// Because SQL INSERTs are triggered in a loop use a tx to ensure a single call to the DB. // Because SQL INSERTs are triggered in a loop use a tx to ensure a single call to the DB.
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{}) tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil { if err != nil {
@ -227,7 +230,7 @@ func (db *Database) StoreIdentityImages(keyUID string, iis []*images.IdentityIma
ii.KeyUID = keyUID ii.KeyUID = keyUID
_, err := tx.Exec( _, err := tx.Exec(
"INSERT INTO identity_images (key_uid, name, image_payload, width, height, file_size, resize_target) VALUES (?, ?, ?, ?, ?, ?, ?)", "INSERT INTO identity_images (key_uid, name, image_payload, width, height, file_size, resize_target, clock) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
ii.KeyUID, ii.KeyUID,
ii.Name, ii.Name,
ii.Payload, ii.Payload,
@ -235,13 +238,16 @@ func (db *Database) StoreIdentityImages(keyUID string, iis []*images.IdentityIma
ii.Height, ii.Height,
ii.FileSize, ii.FileSize,
ii.ResizeTarget, ii.ResizeTarget,
ii.Clock,
) )
if err != nil { if err != nil {
return err return err
} }
} }
if publish {
db.publishOnIdentityImageSubscriptions() db.publishOnIdentityImageSubscriptions()
}
return nil return nil
} }

View File

@ -72,7 +72,7 @@ var (
func seedTestDBWithIdentityImages(t *testing.T, db *Database, keyUID string) { func seedTestDBWithIdentityImages(t *testing.T, db *Database, keyUID string) {
iis := images.SampleIdentityImages() iis := images.SampleIdentityImages()
require.NoError(t, db.StoreIdentityImages(keyUID, iis)) require.NoError(t, db.StoreIdentityImages(keyUID, iis, false))
} }
func TestDatabase_GetIdentityImages(t *testing.T) { func TestDatabase_GetIdentityImages(t *testing.T) {
@ -80,7 +80,7 @@ func TestDatabase_GetIdentityImages(t *testing.T) {
defer stop() defer stop()
seedTestDBWithIdentityImages(t, db, keyUID) seedTestDBWithIdentityImages(t, db, keyUID)
expected := `[{"keyUid":"0xdeadbeef","type":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"fileSize":1024,"resizeTarget":240},{"keyUid":"0xdeadbeef","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80}]` expected := `[{"keyUid":"0xdeadbeef","type":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"fileSize":1024,"resizeTarget":240,"clock":0},{"keyUid":"0xdeadbeef","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80,"clock":0}]`
oiis, err := db.GetIdentityImages(keyUID) oiis, err := db.GetIdentityImages(keyUID)
require.NoError(t, err) require.NoError(t, err)
@ -108,12 +108,12 @@ func TestDatabase_GetIdentityImage(t *testing.T) {
{ {
keyUID, keyUID,
images.SmallDimName, images.SmallDimName,
`{"keyUid":"0xdeadbeef","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80}`, `{"keyUid":"0xdeadbeef","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80,"clock":0}`,
}, },
{ {
keyUID, keyUID,
images.LargeDimName, images.LargeDimName,
`{"keyUid":"0xdeadbeef","type":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"fileSize":1024,"resizeTarget":240}`, `{"keyUid":"0xdeadbeef","type":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"fileSize":1024,"resizeTarget":240,"clock":0}`,
}, },
{ {
keyUID2, keyUID2,
@ -154,7 +154,7 @@ func TestDatabase_GetAccountsWithIdentityImages(t *testing.T) {
{Name: "string", KeyUID: keyUID2 + "2"}, {Name: "string", KeyUID: keyUID2 + "2"},
{Name: "string", KeyUID: keyUID2 + "3"}, {Name: "string", KeyUID: keyUID2 + "3"},
} }
expected := `[{"name":"string","timestamp":100,"identicon":"data","colorHash":null,"colorId":0,"keycard-pairing":"","key-uid":"0xdeadbeef","images":[{"keyUid":"0xdeadbeef","type":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"fileSize":1024,"resizeTarget":240},{"keyUid":"0xdeadbeef","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80}]},{"name":"string","timestamp":10,"identicon":"","colorHash":null,"colorId":0,"keycard-pairing":"","key-uid":"0x1337beef","images":null},{"name":"string","timestamp":0,"identicon":"","colorHash":null,"colorId":0,"keycard-pairing":"","key-uid":"0x1337beef2","images":null},{"name":"string","timestamp":0,"identicon":"","colorHash":null,"colorId":0,"keycard-pairing":"","key-uid":"0x1337beef3","images":[{"keyUid":"0x1337beef3","type":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"fileSize":1024,"resizeTarget":240},{"keyUid":"0x1337beef3","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80}]}]` expected := `[{"name":"string","timestamp":100,"identicon":"data","colorHash":null,"colorId":0,"keycard-pairing":"","key-uid":"0xdeadbeef","images":[{"keyUid":"0xdeadbeef","type":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"fileSize":1024,"resizeTarget":240,"clock":0},{"keyUid":"0xdeadbeef","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80,"clock":0}]},{"name":"string","timestamp":10,"identicon":"","colorHash":null,"colorId":0,"keycard-pairing":"","key-uid":"0x1337beef","images":null},{"name":"string","timestamp":0,"identicon":"","colorHash":null,"colorId":0,"keycard-pairing":"","key-uid":"0x1337beef2","images":null},{"name":"string","timestamp":0,"identicon":"","colorHash":null,"colorId":0,"keycard-pairing":"","key-uid":"0x1337beef3","images":[{"keyUid":"0x1337beef3","type":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"fileSize":1024,"resizeTarget":240,"clock":0},{"keyUid":"0x1337beef3","type":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"fileSize":256,"resizeTarget":80,"clock":0}]}]`
for _, a := range testAccs { for _, a := range testAccs {
require.NoError(t, db.SaveAccount(a)) require.NoError(t, db.SaveAccount(a))

View File

@ -1,20 +1,22 @@
// Code generated by go-bindata. // Code generated by go-bindata. DO NOT EDIT.
// sources: // sources:
// 0001_accounts.down.sql // 0001_accounts.down.sql (21B)
// 0001_accounts.up.sql // 0001_accounts.up.sql (163B)
// 1605007189_identity_images.down.sql // 1605007189_identity_images.down.sql (29B)
// 1605007189_identity_images.up.sql // 1605007189_identity_images.up.sql (268B)
// 1606224181_drop_photo_path_from_accounts.down.sql // 1606224181_drop_photo_path_from_accounts.down.sql (892B)
// 1606224181_drop_photo_path_from_accounts.up.sql // 1606224181_drop_photo_path_from_accounts.up.sql (866B)
// 1649317600_add_color_hash.up.sql // 1648646095_image_clock.down.sql (939B)
// doc.go // 1648646095_image_clock.up.sql (69B)
// DO NOT EDIT! // 1649317600_add_color_hash.up.sql (201B)
// doc.go (74B)
package migrations package migrations
import ( import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"crypto/sha256"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -27,7 +29,7 @@ import (
func bindataRead(data []byte, name string) ([]byte, error) { func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data)) gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil { if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err) return nil, fmt.Errorf("read %q: %v", name, err)
} }
var buf bytes.Buffer var buf bytes.Buffer
@ -35,7 +37,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
clErr := gz.Close() clErr := gz.Close()
if err != nil { if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err) return nil, fmt.Errorf("read %q: %v", name, err)
} }
if clErr != nil { if clErr != nil {
return nil, err return nil, err
@ -47,6 +49,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
type asset struct { type asset struct {
bytes []byte bytes []byte
info os.FileInfo info os.FileInfo
digest [sha256.Size]byte
} }
type bindataFileInfo struct { type bindataFileInfo struct {
@ -90,8 +93,8 @@ func _0001_accountsDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(436), modTime: time.Unix(1649447089, 0)} info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1586880790, 0)}
a := &asset{bytes: bytes, info: info} 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 return a, nil
} }
@ -110,8 +113,8 @@ func _0001_accountsUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(436), modTime: time.Unix(1649447089, 0)} info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1586880790, 0)}
a := &asset{bytes: bytes, info: info} 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 return a, nil
} }
@ -130,8 +133,8 @@ func _1605007189_identity_imagesDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1605007189_identity_images.down.sql", size: 29, mode: os.FileMode(436), modTime: time.Unix(1649447089, 0)} info := bindataFileInfo{name: "1605007189_identity_images.down.sql", size: 29, mode: os.FileMode(0644), modTime: time.Unix(1610470168, 0)}
a := &asset{bytes: bytes, info: info} 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 return a, nil
} }
@ -150,8 +153,8 @@ func _1605007189_identity_imagesUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1605007189_identity_images.up.sql", size: 268, mode: os.FileMode(436), modTime: time.Unix(1649447089, 0)} info := bindataFileInfo{name: "1605007189_identity_images.up.sql", size: 268, mode: os.FileMode(0644), modTime: time.Unix(1610470168, 0)}
a := &asset{bytes: bytes, info: info} 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 return a, nil
} }
@ -170,8 +173,8 @@ func _1606224181_drop_photo_path_from_accountsDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.down.sql", size: 892, mode: os.FileMode(436), modTime: time.Unix(1649447089, 0)} info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.down.sql", size: 892, mode: os.FileMode(0644), modTime: time.Unix(1610470168, 0)}
a := &asset{bytes: bytes, info: info} 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 return a, nil
} }
@ -190,8 +193,48 @@ func _1606224181_drop_photo_path_from_accountsUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.up.sql", size: 866, mode: os.FileMode(436), modTime: time.Unix(1649447089, 0)} info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.up.sql", size: 866, mode: os.FileMode(0644), modTime: time.Unix(1610470168, 0)}
a := &asset{bytes: bytes, info: info} 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
}
var __1648646095_image_clockDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xdc\x92\xbf\x6e\xdb\x30\x18\xc4\x77\x3e\xc5\x8d\x49\x40\x20\x0f\xe0\x49\x56\x68\x84\x28\x2d\xaa\x14\xd3\x34\x93\xc0\x48\x5f\x25\x22\xfa\x07\x89\x42\xe0\x3e\x7d\x61\xd9\xb0\x6b\xa3\xf5\xd6\xa5\xe3\x77\x3c\x92\x77\xfc\xf1\xf1\x01\xd9\x57\xe5\x03\xa1\xec\x69\x42\xd7\x07\x4c\xf3\x30\xf4\x63\x40\x39\xf6\xc3\xe0\xbb\x0a\x45\xdf\xcc\x6d\x37\x71\xd4\xd4\x15\x84\x4f\x42\x3b\x4f\x01\xc5\x48\x2e\x10\x1c\x02\xb5\x03\x82\x7b\x6f\x08\x0f\x8f\x2c\x36\x22\xb2\x02\x56\x6c\x53\x6d\x22\xf3\x06\x1b\xad\x95\x80\x2f\xa9\x0b\x3e\xec\x72\xdf\xba\x8a\xa6\xfc\xdd\x15\x1f\xf3\x70\xc7\x00\xe0\x83\x76\xf9\xec\x4b\x7c\x8b\x4c\xfc\x1c\x19\xbe\x88\x9d\x6b\xe9\x52\x59\x76\xe6\x83\xdb\x35\xbd\x2b\xb1\x56\x7a\x8d\x44\x5b\x24\x2f\x4a\x1d\x0c\x9f\xbe\x0c\x35\x7c\x17\x0e\x63\x4d\xbe\xaa\xc3\x79\xfe\xe1\x1b\xca\x27\xff\x93\xce\xd2\x48\xfb\x39\x0f\x6e\xac\xe8\x37\x67\x6a\xe4\x76\x1f\xfd\x8b\x78\xc3\xdd\x31\x1d\x5f\x12\xdd\x43\x27\x88\x75\xb2\x51\x32\xb6\x30\x22\x55\x51\x2c\xd8\x3d\x5e\xa5\x7d\xd6\x2f\x16\x46\xbf\xca\xa7\x15\x63\x32\xc9\x84\xb1\x90\x89\xd5\x7f\xa9\x8e\x4c\x28\x11\x5b\x5c\x1c\xcf\x2f\x4b\xf2\x43\x25\x7e\xac\xc2\xcf\x15\xf8\x55\xf4\x8d\xd1\xdb\xeb\x8b\x56\x8c\x3d\x19\x9d\xfe\x19\xc0\x8a\xb1\x13\xaa\x65\x5d\x6e\x96\xd7\x14\xdf\x65\x66\xb3\x6b\xf7\x7f\xcb\xe9\x16\xa8\x7f\x4f\xe8\xf8\x15\x6e\x82\x3a\x79\x7e\x05\x00\x00\xff\xff\xce\x2f\xe3\x37\xab\x03\x00\x00")
func _1648646095_image_clockDownSqlBytes() ([]byte, error) {
return bindataRead(
__1648646095_image_clockDownSql,
"1648646095_image_clock.down.sql",
)
}
func _1648646095_image_clockDownSql() (*asset, error) {
bytes, err := _1648646095_image_clockDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1648646095_image_clock.down.sql", size: 939, mode: os.FileMode(0644), modTime: time.Unix(1650538025, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4d, 0xa8, 0x1f, 0xf, 0xe0, 0xd7, 0xc9, 0x68, 0x98, 0xd8, 0x37, 0xb8, 0xba, 0x9e, 0xb2, 0x19, 0xf3, 0xc4, 0x73, 0x80, 0x3, 0x17, 0x2a, 0x53, 0x68, 0x10, 0x13, 0x54, 0x99, 0xb1, 0xf5, 0x1c}}
return a, nil
}
var __1648646095_image_clockUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\xc8\x4c\x49\xcd\x2b\xc9\x2c\xa9\x8c\xcf\xcc\x4d\x4c\x4f\x2d\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\xce\xc9\x4f\xce\x56\xf0\xf4\x0b\x51\xf0\xf3\x0f\x51\xf0\x0b\xf5\xf1\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x30\xb0\xe6\x02\x04\x00\x00\xff\xff\x22\x35\x20\xbf\x45\x00\x00\x00")
func _1648646095_image_clockUpSqlBytes() ([]byte, error) {
return bindataRead(
__1648646095_image_clockUpSql,
"1648646095_image_clock.up.sql",
)
}
func _1648646095_image_clockUpSql() (*asset, error) {
bytes, err := _1648646095_image_clockUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1648646095_image_clock.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1650537691, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x98, 0xa6, 0xa4, 0x4e, 0x4e, 0xca, 0x17, 0x56, 0xea, 0xfb, 0xf0, 0xa9, 0x81, 0x95, 0xe, 0x80, 0x52, 0x1, 0x47, 0x9b, 0xde, 0x14, 0xfa, 0x72, 0xc9, 0x62, 0x6f, 0x24, 0xa2, 0xc, 0x32, 0x50}}
return a, nil return a, nil
} }
@ -210,8 +253,8 @@ func _1649317600_add_color_hashUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1649317600_add_color_hash.up.sql", size: 201, mode: os.FileMode(436), modTime: time.Unix(1649447080, 0)} info := bindataFileInfo{name: "1649317600_add_color_hash.up.sql", size: 201, mode: os.FileMode(0644), modTime: time.Unix(1650537691, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1a, 0xf, 0x37, 0x6d, 0xcf, 0x99, 0xc9, 0x2e, 0xdc, 0x70, 0x11, 0xb4, 0x36, 0x26, 0x4f, 0x39, 0xa8, 0x44, 0xf, 0xcb, 0xcc, 0x81, 0x74, 0x7a, 0x88, 0xaa, 0x54, 0x8c, 0xc4, 0xe, 0x56, 0x4f}}
return a, nil return a, nil
} }
@ -230,8 +273,8 @@ func docGo() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(436), modTime: time.Unix(1649447089, 0)} info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1586880790, 0)}
a := &asset{bytes: bytes, info: info} 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 return a, nil
} }
@ -239,8 +282,8 @@ func docGo() (*asset, error) {
// It returns an error if the asset could not be found or // It returns an error if the asset could not be found or
// could not be loaded. // could not be loaded.
func Asset(name string) ([]byte, error) { func Asset(name string) ([]byte, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok { if f, ok := _bindata[canonicalName]; ok {
a, err := f() a, err := f()
if err != nil { if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
@ -250,6 +293,12 @@ func Asset(name string) ([]byte, error) {
return nil, fmt.Errorf("Asset %s not found", name) return nil, fmt.Errorf("Asset %s not found", name)
} }
// AssetString returns the asset contents as a string (instead of a []byte).
func AssetString(name string) (string, error) {
data, err := Asset(name)
return string(data), err
}
// MustAsset is like Asset but panics when Asset would return an error. // MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables. // It simplifies safe initialization of global variables.
func MustAsset(name string) []byte { func MustAsset(name string) []byte {
@ -261,12 +310,18 @@ func MustAsset(name string) []byte {
return a return a
} }
// MustAssetString is like AssetString but panics when Asset would return an
// error. It simplifies safe initialization of global variables.
func MustAssetString(name string) string {
return string(MustAsset(name))
}
// AssetInfo loads and returns the asset info for the given name. // AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or // It returns an error if the asset could not be found or
// could not be loaded. // could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) { func AssetInfo(name string) (os.FileInfo, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok { if f, ok := _bindata[canonicalName]; ok {
a, err := f() a, err := f()
if err != nil { if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
@ -276,6 +331,33 @@ func AssetInfo(name string) (os.FileInfo, error) {
return nil, fmt.Errorf("AssetInfo %s not found", name) return nil, fmt.Errorf("AssetInfo %s not found", name)
} }
// AssetDigest returns the digest of the file with the given name. It returns an
// error if the asset could not be found or the digest could not be loaded.
func AssetDigest(name string) ([sha256.Size]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err)
}
return a.digest, nil
}
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name)
}
// Digests returns a map of all known files and their checksums.
func Digests() (map[string][sha256.Size]byte, error) {
mp := make(map[string][sha256.Size]byte, len(_bindata))
for name := range _bindata {
a, err := _bindata[name]()
if err != nil {
return nil, err
}
mp[name] = a.digest
}
return mp, nil
}
// AssetNames returns the names of the assets. // AssetNames returns the names of the assets.
func AssetNames() []string { func AssetNames() []string {
names := make([]string, 0, len(_bindata)) names := make([]string, 0, len(_bindata))
@ -288,12 +370,23 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name. // _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){ var _bindata = map[string]func() (*asset, error){
"0001_accounts.down.sql": _0001_accountsDownSql, "0001_accounts.down.sql": _0001_accountsDownSql,
"0001_accounts.up.sql": _0001_accountsUpSql, "0001_accounts.up.sql": _0001_accountsUpSql,
"1605007189_identity_images.down.sql": _1605007189_identity_imagesDownSql, "1605007189_identity_images.down.sql": _1605007189_identity_imagesDownSql,
"1605007189_identity_images.up.sql": _1605007189_identity_imagesUpSql, "1605007189_identity_images.up.sql": _1605007189_identity_imagesUpSql,
"1606224181_drop_photo_path_from_accounts.down.sql": _1606224181_drop_photo_path_from_accountsDownSql, "1606224181_drop_photo_path_from_accounts.down.sql": _1606224181_drop_photo_path_from_accountsDownSql,
"1606224181_drop_photo_path_from_accounts.up.sql": _1606224181_drop_photo_path_from_accountsUpSql, "1606224181_drop_photo_path_from_accounts.up.sql": _1606224181_drop_photo_path_from_accountsUpSql,
"1648646095_image_clock.down.sql": _1648646095_image_clockDownSql,
"1648646095_image_clock.up.sql": _1648646095_image_clockUpSql,
"1649317600_add_color_hash.up.sql": _1649317600_add_color_hashUpSql, "1649317600_add_color_hash.up.sql": _1649317600_add_color_hashUpSql,
"doc.go": docGo, "doc.go": docGo,
} }
@ -306,15 +399,15 @@ var _bindata = map[string]func() (*asset, error){
// img/ // img/
// a.png // a.png
// b.png // b.png
// then AssetDir("data") would return []string{"foo.txt", "img"} // then AssetDir("data") would return []string{"foo.txt", "img"},
// AssetDir("data/img") would return []string{"a.png", "b.png"} // AssetDir("data/img") would return []string{"a.png", "b.png"},
// AssetDir("foo.txt") and AssetDir("notexist") would return an error // AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
// AssetDir("") will return []string{"data"}. // AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) { func AssetDir(name string) ([]string, error) {
node := _bintree node := _bintree
if len(name) != 0 { if len(name) != 0 {
cannonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(cannonicalName, "/") pathList := strings.Split(canonicalName, "/")
for _, p := range pathList { for _, p := range pathList {
node = node.Children[p] node = node.Children[p]
if node == nil { if node == nil {
@ -336,6 +429,7 @@ type bintree struct {
Func func() (*asset, error) Func func() (*asset, error)
Children map[string]*bintree Children map[string]*bintree
} }
var _bintree = &bintree{nil, map[string]*bintree{ var _bintree = &bintree{nil, map[string]*bintree{
"0001_accounts.down.sql": &bintree{_0001_accountsDownSql, map[string]*bintree{}}, "0001_accounts.down.sql": &bintree{_0001_accountsDownSql, map[string]*bintree{}},
"0001_accounts.up.sql": &bintree{_0001_accountsUpSql, map[string]*bintree{}}, "0001_accounts.up.sql": &bintree{_0001_accountsUpSql, map[string]*bintree{}},
@ -343,11 +437,13 @@ var _bintree = &bintree{nil, map[string]*bintree{
"1605007189_identity_images.up.sql": &bintree{_1605007189_identity_imagesUpSql, map[string]*bintree{}}, "1605007189_identity_images.up.sql": &bintree{_1605007189_identity_imagesUpSql, map[string]*bintree{}},
"1606224181_drop_photo_path_from_accounts.down.sql": &bintree{_1606224181_drop_photo_path_from_accountsDownSql, map[string]*bintree{}}, "1606224181_drop_photo_path_from_accounts.down.sql": &bintree{_1606224181_drop_photo_path_from_accountsDownSql, map[string]*bintree{}},
"1606224181_drop_photo_path_from_accounts.up.sql": &bintree{_1606224181_drop_photo_path_from_accountsUpSql, map[string]*bintree{}}, "1606224181_drop_photo_path_from_accounts.up.sql": &bintree{_1606224181_drop_photo_path_from_accountsUpSql, map[string]*bintree{}},
"1648646095_image_clock.down.sql": &bintree{_1648646095_image_clockDownSql, map[string]*bintree{}},
"1648646095_image_clock.up.sql": &bintree{_1648646095_image_clockUpSql, map[string]*bintree{}},
"1649317600_add_color_hash.up.sql": &bintree{_1649317600_add_color_hashUpSql, map[string]*bintree{}}, "1649317600_add_color_hash.up.sql": &bintree{_1649317600_add_color_hashUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, 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.
func RestoreAsset(dir, name string) error { func RestoreAsset(dir, name string) error {
data, err := Asset(name) data, err := Asset(name)
if err != nil { if err != nil {
@ -365,14 +461,10 @@ func RestoreAsset(dir, name string) error {
if err != nil { if err != nil {
return err return err
} }
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
if err != nil {
return err
}
return nil
} }
// RestoreAssets restores an asset under the given directory recursively // RestoreAssets restores an asset under the given directory recursively.
func RestoreAssets(dir, name string) error { func RestoreAssets(dir, name string) error {
children, err := AssetDir(name) children, err := AssetDir(name)
// File // File
@ -390,7 +482,6 @@ func RestoreAssets(dir, name string) error {
} }
func _filePath(dir, name string) string { func _filePath(dir, name string) string {
cannonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...)
} }

View File

@ -0,0 +1,32 @@
/* SQLite does not support dropping columns, hence we must create a temp table */
CREATE TEMPORARY TABLE identity_images_backup(
key_uid VARCHAR,
name VARCHAR,
image_payload BLOB NOT NULL,
width int,
height int,
file_size int,
resize_target int,
PRIMARY KEY (key_uid, name) ON CONFLICT REPLACE
) WITHOUT ROWID;
INSERT INTO identity_images_backup SELECT key_uid, name, image_payload, width, height, file_size, resize_target FROM identity_images;
DROP TABLE identity_images;
CREATE TABLE IF NOT EXISTS identity_images(
key_uid VARCHAR,
name VARCHAR,
image_payload BLOB NOT NULL,
width int,
height int,
file_size int,
resize_target int,
PRIMARY KEY (key_uid, name) ON CONFLICT REPLACE
) WITHOUT ROWID;
INSERT INTO identity_images SELECT key_uid, name, image_payload, width, height, file_size, resize_target FROM identity_images_backup;
DROP TABLE identity_images_backup;

View File

@ -0,0 +1 @@
ALTER TABLE identity_images ADD COLUMN clock INT NOT NULL DEFAULT 0;

View File

@ -1199,7 +1199,11 @@ func (m *Messenger) watchIdentityImageChanges() {
for { for {
select { select {
case <-channel: case <-channel:
err := m.PublishIdentityImage() err := m.syncProfilePictures()
if err != nil {
m.logger.Error("failed to sync profile pictures to paired devices", zap.Error(err))
}
err = m.PublishIdentityImage()
if err != nil { if err != nil {
m.logger.Error("failed to publish identity image", zap.Error(err)) m.logger.Error("failed to publish identity image", zap.Error(err))
} }
@ -2562,6 +2566,61 @@ func (m *Messenger) ShareImageMessage(request *requests.ShareImageMessage) (*Mes
return response, nil return response, nil
} }
func (m *Messenger) syncProfilePictures() error {
if !m.hasPairedDevices() {
return nil
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
keyUID := m.account.KeyUID
images, err := m.multiAccounts.GetIdentityImages(keyUID)
if err != nil {
return err
}
pictures := make([]*protobuf.SyncProfilePicture, len(images))
clock, chat := m.getLastClockWithRelatedChat()
for i, image := range images {
p := &protobuf.SyncProfilePicture{}
p.Name = image.Name
p.Payload = image.Payload
p.Width = uint32(image.Width)
p.Height = uint32(image.Height)
p.FileSize = uint32(image.FileSize)
p.ResizeTarget = uint32(image.ResizeTarget)
if image.Clock == 0 {
p.Clock = clock
} else {
p.Clock = image.Clock
}
pictures[i] = p
}
message := &protobuf.SyncProfilePictures{}
message.KeyUid = keyUID
message.Pictures = pictures
encodedMessage, err := proto.Marshal(message)
if err != nil {
return err
}
_, err = m.dispatchMessage(ctx, common.RawMessage{
LocalChatID: chat.ID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_SYNC_PROFILE_PICTURE,
ResendAutomatically: true,
})
if err != nil {
return err
}
chat.LastClockValue = clock
return m.saveChat(chat)
}
// SyncDevices sends all public chats and contacts to paired devices // SyncDevices sends all public chats and contacts to paired devices
// TODO remove use of photoPath in contacts // TODO remove use of photoPath in contacts
func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string) (err error) { func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string) (err error) {
@ -2654,6 +2713,11 @@ func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string)
return err return err
} }
err = m.syncProfilePictures()
if err != nil {
return err
}
return err return err
} }
@ -3299,6 +3363,21 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
continue continue
} }
case protobuf.SyncProfilePictures:
if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
logger.Warn("not coming from us, ignoring")
continue
}
p := msg.ParsedMessage.Interface().(protobuf.SyncProfilePictures)
logger.Debug("Handling SyncProfilePicture", zap.Any("message", p))
err = m.HandleSyncProfilePictures(messageState, p)
if err != nil {
logger.Warn("failed to handle SyncProfilePicture", zap.Error(err))
allMessagesProcessed = false
continue
}
case protobuf.SyncBookmark: case protobuf.SyncBookmark:
if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) { if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
logger.Warn("not coming from us, ignoring") logger.Warn("not coming from us, ignoring")

View File

@ -419,6 +419,46 @@ func (m *Messenger) HandleSyncInstallationContact(state *ReceivedMessageState, m
return nil return nil
} }
func (m *Messenger) HandleSyncProfilePictures(state *ReceivedMessageState, message protobuf.SyncProfilePictures) error {
dbImages, err := m.multiAccounts.GetIdentityImages(message.KeyUid)
if err != nil {
return err
}
dbImageMap := make(map[string]*images.IdentityImage)
for _, img := range dbImages {
dbImageMap[img.Name] = img
}
idImages := make([]*images.IdentityImage, len(message.Pictures))
i := 0
for _, message := range message.Pictures {
dbImg := dbImageMap[message.Name]
if dbImg != nil && message.Clock <= dbImg.Clock {
continue
}
image := &images.IdentityImage{
Name: message.Name,
Payload: message.Payload,
Width: int(message.Width),
Height: int(message.Height),
FileSize: int(message.FileSize),
ResizeTarget: int(message.ResizeTarget),
Clock: message.Clock,
}
idImages[i] = image
i++
}
if i == 0 {
return nil
}
err = m.multiAccounts.StoreIdentityImages(message.KeyUid, idImages[:i], false)
if err == nil {
state.Response.IdentityImages = idImages[:i]
}
return err
}
func (m *Messenger) HandleSyncInstallationPublicChat(state *ReceivedMessageState, message protobuf.SyncInstallationPublicChat) *Chat { func (m *Messenger) HandleSyncInstallationPublicChat(state *ReceivedMessageState, message protobuf.SyncInstallationPublicChat) *Chat {
chatID := message.Id chatID := message.Id
existingChat, ok := state.AllChats.Load(chatID) existingChat, ok := state.AllChats.Load(chatID)

View File

@ -129,7 +129,7 @@ func (s *MessengerProfilePictureHandlerSuite) setupMultiAccount(m *Messenger) {
func (s *MessengerProfilePictureHandlerSuite) generateAndStoreIdentityImages(m *Messenger) []*images.IdentityImage { func (s *MessengerProfilePictureHandlerSuite) generateAndStoreIdentityImages(m *Messenger) []*images.IdentityImage {
keyUID := s.generateKeyUID(&m.identity.PublicKey) keyUID := s.generateKeyUID(&m.identity.PublicKey)
iis := images.SampleIdentityImages() iis := images.SampleIdentityImages()
s.Require().NoError(m.multiAccounts.StoreIdentityImages(keyUID, iis)) s.Require().NoError(m.multiAccounts.StoreIdentityImages(keyUID, iis, false))
return iis return iis
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/status-im/status-go/services/browsers" "github.com/status-im/status-go/services/browsers"
"github.com/status-im/status-go/appmetrics" "github.com/status-im/status-go/appmetrics"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/multiaccounts/settings"
"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"
@ -35,6 +36,7 @@ type MessengerResponse struct {
Mailservers []mailservers.Mailserver Mailservers []mailservers.Mailserver
Bookmarks []*browsers.Bookmark Bookmarks []*browsers.Bookmark
Settings []*settings.SyncSettingField Settings []*settings.SyncSettingField
IdentityImages []*images.IdentityImage
// notifications a list of notifications derived from messenger events // notifications a list of notifications derived from messenger events
// that are useful to notify the user about // that are useful to notify the user about
@ -77,6 +79,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
CurrentStatus *UserStatus `json:"currentStatus,omitempty"` CurrentStatus *UserStatus `json:"currentStatus,omitempty"`
StatusUpdates []UserStatus `json:"statusUpdates,omitempty"` StatusUpdates []UserStatus `json:"statusUpdates,omitempty"`
Settings []*settings.SyncSettingField `json:"settings,omitempty"` Settings []*settings.SyncSettingField `json:"settings,omitempty"`
IdentityImages []*images.IdentityImage `json:"identityImages,omitempty"`
}{ }{
Contacts: r.Contacts, Contacts: r.Contacts,
Installations: r.Installations, Installations: r.Installations,
@ -88,7 +91,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
Bookmarks: r.Bookmarks, Bookmarks: r.Bookmarks,
CurrentStatus: r.currentStatus, CurrentStatus: r.currentStatus,
Settings: r.Settings, Settings: r.Settings,
IdentityImages: r.IdentityImages,
Messages: r.Messages(), Messages: r.Messages(),
Notifications: r.Notifications(), Notifications: r.Notifications(),
Chats: r.Chats(), Chats: r.Chats(),
@ -194,6 +197,7 @@ func (r *MessengerResponse) IsEmpty() bool {
len(r.removedChats)+ len(r.removedChats)+
len(r.removedMessages)+ len(r.removedMessages)+
len(r.Mailservers)+ len(r.Mailservers)+
len(r.IdentityImages)+
len(r.notifications)+ len(r.notifications)+
len(r.statusUpdates)+ len(r.statusUpdates)+
len(r.activityCenterNotifications)+ len(r.activityCenterNotifications)+

View File

@ -0,0 +1,184 @@
package protocol
import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"testing"
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/images"
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/waku"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/types"
)
func TestMessengerSyncProfilePictureSuite(t *testing.T) {
suite.Run(t, new(MessengerSyncProfilePictureSuite))
}
type MessengerSyncProfilePictureSuite struct {
suite.Suite
m *Messenger // main instance of Messenger
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
// If one wants to send messages between different instances of Messenger,
// a single Waku service should be shared.
shh types.Waku
logger *zap.Logger
}
func (s *MessengerSyncProfilePictureSuite) SetupTest() {
s.logger = tt.MustCreateTestLogger()
config := waku.DefaultConfig
config.MinimumAcceptedPoW = 0
shh := waku.New(&config, s.logger)
s.shh = gethbridge.NewGethWakuWrapper(shh)
s.Require().NoError(shh.Start())
s.m = s.newMessenger(s.shh)
s.privateKey = s.m.identity
// We start the messenger in order to receive installations
_, err := s.m.Start()
s.Require().NoError(err)
}
func (s *MessengerSyncProfilePictureSuite) TearDownTest() {
s.Require().NoError(s.m.Shutdown())
}
func (s *MessengerSyncProfilePictureSuite) newMessenger(shh types.Waku) *Messenger {
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
messenger, err := newMessengerWithKey(s.shh, privateKey, s.logger, nil)
s.Require().NoError(err)
return messenger
}
func (s *MessengerSyncProfilePictureSuite) TestSyncProfilePicture() {
// Add identity images
keyUID := s.m.account.KeyUID
// pair
theirMessenger, err := newMessengerWithKey(s.shh, s.privateKey, s.logger, nil)
s.Require().NoError(err)
err = theirMessenger.SetInstallationMetadata(theirMessenger.installationID, &multidevice.InstallationMetadata{
Name: "their-name",
DeviceType: "their-device-type",
})
s.Require().NoError(err)
response, err := theirMessenger.SendPairInstallation(context.Background())
s.Require().NoError(err)
s.Require().NotNil(response)
s.Require().Len(response.Chats(), 1)
s.Require().False(response.Chats()[0].Active)
// Wait for the message to reach its destination
response, err = WaitOnMessengerResponse(
s.m,
func(r *MessengerResponse) bool { return len(r.Installations) > 0 },
"installation not received",
)
s.Require().NoError(err)
actualInstallation := response.Installations[0]
s.Require().Equal(theirMessenger.installationID, actualInstallation.ID)
s.Require().NotNil(actualInstallation.InstallationMetadata)
s.Require().Equal("their-name", actualInstallation.InstallationMetadata.Name)
s.Require().Equal("their-device-type", actualInstallation.InstallationMetadata.DeviceType)
err = s.m.EnableInstallation(theirMessenger.installationID)
s.Require().NoError(err)
// Sync happens via subscription triggered from within StoreIdentityImages
const (
lowClock = 5
highClock = 10
)
iis := images.SampleIdentityImages()
for _, img := range iis {
img.Clock = highClock
}
s.Require().NoError(s.m.multiAccounts.StoreIdentityImages(keyUID, iis, true))
// Wait for the message to reach its destination
err = tt.RetryWithBackOff(func() error {
response, err = theirMessenger.RetrieveAll()
if err != nil {
return err
}
syncedImages, err := theirMessenger.multiAccounts.GetIdentityImages(keyUID)
if err != nil {
return err
}
if len(syncedImages) == 2 {
return nil
}
return errors.New("Not received all identity images")
})
s.Require().NoError(err)
syncedImages, err := theirMessenger.multiAccounts.GetIdentityImages(keyUID)
s.Require().NoError(err)
s.Require().Equal(2, len(syncedImages))
s.Require().Equal(2, len(response.IdentityImages))
// Check that we don't update images with earlier clock values
for _, img := range iis {
img.Clock = lowClock
}
iis2 := images.SampleIdentityImages()
for i, img := range iis2 {
img.Name = fmt.Sprintf("newimg%d", i)
img.Clock = highClock
}
iis = append(iis, iis2...)
s.Require().NoError(s.m.multiAccounts.StoreIdentityImages(keyUID, iis, true))
err = tt.RetryWithBackOff(func() error {
response, err = theirMessenger.RetrieveAll()
if err != nil {
return err
}
syncedImages, err := theirMessenger.multiAccounts.GetIdentityImages(keyUID)
if err != nil {
return err
}
if len(syncedImages) == 4 {
return nil
}
return errors.New("Not received all identity images")
})
syncedImages, err = theirMessenger.multiAccounts.GetIdentityImages(keyUID)
s.Require().NoError(err)
s.Require().Equal(4, len(syncedImages))
for _, img := range syncedImages {
s.Require().NotEqual(img.Clock, lowClock)
}
s.Require().NoError(theirMessenger.Shutdown())
}

View File

@ -1,4 +1,4 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: application_metadata_message.proto // source: application_metadata_message.proto
package protobuf package protobuf
@ -6,7 +6,9 @@ package protobuf
import ( import (
fmt "fmt" fmt "fmt"
proto "github.com/golang/protobuf/proto" proto "github.com/golang/protobuf/proto"
io "io"
math "math" math "math"
math_bits "math/bits"
) )
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -67,6 +69,7 @@ const (
ApplicationMetadataMessage_SYNC_CLEAR_HISTORY ApplicationMetadataMessage_Type = 41 ApplicationMetadataMessage_SYNC_CLEAR_HISTORY ApplicationMetadataMessage_Type = 41
ApplicationMetadataMessage_SYNC_SETTING ApplicationMetadataMessage_Type = 42 ApplicationMetadataMessage_SYNC_SETTING ApplicationMetadataMessage_Type = 42
ApplicationMetadataMessage_COMMUNITY_ARCHIVE_MAGNETLINK ApplicationMetadataMessage_Type = 43 ApplicationMetadataMessage_COMMUNITY_ARCHIVE_MAGNETLINK ApplicationMetadataMessage_Type = 43
ApplicationMetadataMessage_SYNC_PROFILE_PICTURE ApplicationMetadataMessage_Type = 44
) )
var ApplicationMetadataMessage_Type_name = map[int32]string{ var ApplicationMetadataMessage_Type_name = map[int32]string{
@ -114,6 +117,7 @@ var ApplicationMetadataMessage_Type_name = map[int32]string{
41: "SYNC_CLEAR_HISTORY", 41: "SYNC_CLEAR_HISTORY",
42: "SYNC_SETTING", 42: "SYNC_SETTING",
43: "COMMUNITY_ARCHIVE_MAGNETLINK", 43: "COMMUNITY_ARCHIVE_MAGNETLINK",
44: "SYNC_PROFILE_PICTURE",
} }
var ApplicationMetadataMessage_Type_value = map[string]int32{ var ApplicationMetadataMessage_Type_value = map[string]int32{
@ -161,6 +165,7 @@ var ApplicationMetadataMessage_Type_value = map[string]int32{
"SYNC_CLEAR_HISTORY": 41, "SYNC_CLEAR_HISTORY": 41,
"SYNC_SETTING": 42, "SYNC_SETTING": 42,
"COMMUNITY_ARCHIVE_MAGNETLINK": 43, "COMMUNITY_ARCHIVE_MAGNETLINK": 43,
"SYNC_PROFILE_PICTURE": 44,
} }
func (x ApplicationMetadataMessage_Type) String() string { func (x ApplicationMetadataMessage_Type) String() string {
@ -189,18 +194,26 @@ func (*ApplicationMetadataMessage) ProtoMessage() {}
func (*ApplicationMetadataMessage) Descriptor() ([]byte, []int) { func (*ApplicationMetadataMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_ad09a6406fcf24c7, []int{0} return fileDescriptor_ad09a6406fcf24c7, []int{0}
} }
func (m *ApplicationMetadataMessage) XXX_Unmarshal(b []byte) error { func (m *ApplicationMetadataMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplicationMetadataMessage.Unmarshal(m, b) return m.Unmarshal(b)
} }
func (m *ApplicationMetadataMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { func (m *ApplicationMetadataMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_ApplicationMetadataMessage.Marshal(b, m, deterministic) return xxx_messageInfo_ApplicationMetadataMessage.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
} }
func (m *ApplicationMetadataMessage) XXX_Merge(src proto.Message) { func (m *ApplicationMetadataMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplicationMetadataMessage.Merge(m, src) xxx_messageInfo_ApplicationMetadataMessage.Merge(m, src)
} }
func (m *ApplicationMetadataMessage) XXX_Size() int { func (m *ApplicationMetadataMessage) XXX_Size() int {
return xxx_messageInfo_ApplicationMetadataMessage.Size(m) return m.Size()
} }
func (m *ApplicationMetadataMessage) XXX_DiscardUnknown() { func (m *ApplicationMetadataMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ApplicationMetadataMessage.DiscardUnknown(m) xxx_messageInfo_ApplicationMetadataMessage.DiscardUnknown(m)
@ -239,51 +252,363 @@ func init() {
} }
var fileDescriptor_ad09a6406fcf24c7 = []byte{ var fileDescriptor_ad09a6406fcf24c7 = []byte{
// 735 bytes of a gzipped FileDescriptorProto // 775 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0x5d, 0x53, 0x1b, 0x37, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0xdd, 0x72, 0x13, 0x37,
0x14, 0xad, 0x13, 0x0a, 0xe1, 0x1a, 0x88, 0x50, 0xf8, 0x30, 0xe6, 0xcb, 0x71, 0xd2, 0x84, 0x24, 0x14, 0xc6, 0x90, 0x26, 0xe4, 0x24, 0x04, 0x45, 0xe4, 0xc7, 0xf9, 0xb1, 0x63, 0x0c, 0x85, 0x00,
0x33, 0xee, 0x4c, 0xfb, 0xd8, 0xe9, 0x83, 0x2c, 0xdd, 0xd8, 0x8a, 0xbd, 0xd2, 0x46, 0xd2, 0xba, 0x1d, 0x77, 0xa6, 0xbd, 0xec, 0xf4, 0x42, 0x96, 0x4e, 0x6c, 0xe1, 0x5d, 0x69, 0x91, 0xb4, 0xee,
0xe3, 0xbe, 0x68, 0x36, 0x8d, 0xcb, 0x30, 0x03, 0xd8, 0x03, 0xe6, 0x81, 0xbf, 0xd8, 0x5f, 0xd1, 0xb8, 0x37, 0x9a, 0xa5, 0xb8, 0x4c, 0x66, 0x00, 0x7b, 0x88, 0xb9, 0xc8, 0x9b, 0xf4, 0x91, 0x7a,
0x9f, 0xd2, 0xd1, 0xae, 0xed, 0x35, 0x60, 0xca, 0x93, 0xad, 0x73, 0x8e, 0xee, 0xd5, 0x3d, 0xf7, 0xd9, 0x47, 0xe8, 0xa4, 0x7d, 0x8a, 0x5e, 0x75, 0xb4, 0x6b, 0x7b, 0x0d, 0x31, 0x70, 0x65, 0xeb,
0xde, 0x85, 0x7a, 0x3a, 0x1a, 0x9d, 0x9f, 0xfd, 0x95, 0x8e, 0xcf, 0x86, 0x97, 0xfe, 0x62, 0x30, 0xfb, 0xbe, 0xa3, 0xa3, 0xf3, 0x9d, 0x73, 0x16, 0x9a, 0xd9, 0x78, 0xfc, 0xe6, 0xfc, 0xb7, 0x6c,
0x4e, 0xbf, 0xa7, 0xe3, 0xd4, 0x5f, 0x0c, 0xae, 0xaf, 0xd3, 0xd3, 0x41, 0x63, 0x74, 0x35, 0x1c, 0x72, 0x3e, 0x7a, 0xe7, 0xdf, 0x0e, 0x27, 0xd9, 0xab, 0x6c, 0x92, 0xf9, 0xb7, 0xc3, 0x8b, 0x8b,
0x0f, 0xe9, 0x8b, 0xec, 0xe7, 0xdb, 0xcd, 0xdf, 0xf5, 0x7f, 0x01, 0xaa, 0xac, 0xb8, 0x10, 0x4d, 0xec, 0xf5, 0xb0, 0x35, 0x7e, 0x3f, 0x9a, 0x8c, 0xe8, 0xed, 0xfc, 0xe7, 0xe5, 0x87, 0xdf, 0x9b,
0xf4, 0x51, 0x2e, 0xa7, 0x07, 0xb0, 0x7a, 0x7d, 0x76, 0x7a, 0x99, 0x8e, 0x6f, 0xae, 0x06, 0x95, 0xff, 0x01, 0x1c, 0xb2, 0x32, 0x20, 0x9e, 0xea, 0xe3, 0x42, 0x4e, 0x8f, 0x61, 0xfd, 0xe2, 0xfc,
0x52, 0xad, 0x74, 0xb2, 0x66, 0x0a, 0x80, 0x56, 0x60, 0x65, 0x94, 0xde, 0x9e, 0x0f, 0xd3, 0xef, 0xf5, 0xbb, 0x6c, 0xf2, 0xe1, 0xfd, 0xb0, 0x5a, 0x69, 0x54, 0x4e, 0x37, 0x4d, 0x09, 0xd0, 0x2a,
0x95, 0x67, 0x19, 0x37, 0x3d, 0xd2, 0xdf, 0x61, 0x69, 0x7c, 0x3b, 0x1a, 0x54, 0x9e, 0xd7, 0x4a, 0xac, 0x8d, 0xb3, 0xcb, 0x37, 0xa3, 0xec, 0x55, 0xf5, 0x66, 0xce, 0xcd, 0x8e, 0xf4, 0x67, 0x58,
0x27, 0x1b, 0xbf, 0x7c, 0x68, 0x4c, 0xf3, 0x35, 0x1e, 0xcf, 0xd5, 0x70, 0xb7, 0xa3, 0x81, 0xc9, 0x99, 0x5c, 0x8e, 0x87, 0xd5, 0x5b, 0x8d, 0xca, 0xe9, 0xd6, 0x0f, 0x4f, 0x5a, 0xb3, 0x7c, 0xad,
0xae, 0xd5, 0xff, 0x59, 0x85, 0xa5, 0x70, 0xa4, 0x65, 0x58, 0x49, 0x54, 0x47, 0xe9, 0x3f, 0x14, 0xcf, 0xe7, 0x6a, 0xb9, 0xcb, 0xf1, 0xd0, 0xe4, 0x61, 0xcd, 0x7f, 0xd7, 0x61, 0x25, 0x1c, 0xe9,
0xf9, 0x81, 0x12, 0x58, 0xe3, 0x6d, 0xe6, 0x7c, 0x84, 0xd6, 0xb2, 0x16, 0x92, 0x12, 0xa5, 0xb0, 0x06, 0xac, 0xa5, 0xaa, 0xa7, 0xf4, 0x2f, 0x8a, 0xdc, 0xa0, 0x04, 0x36, 0x79, 0x97, 0x39, 0x1f,
0xc1, 0xb5, 0x72, 0x8c, 0x3b, 0x9f, 0xc4, 0x82, 0x39, 0x24, 0xcf, 0xe8, 0x21, 0xec, 0x45, 0x18, 0xa3, 0xb5, 0xac, 0x83, 0xa4, 0x42, 0x29, 0x6c, 0x71, 0xad, 0x1c, 0xe3, 0xce, 0xa7, 0x89, 0x60,
0x35, 0xd1, 0xd8, 0xb6, 0x8c, 0x27, 0xf0, 0xec, 0xca, 0x73, 0xba, 0x0d, 0x9b, 0x31, 0x93, 0xc6, 0x0e, 0xc9, 0x4d, 0x5a, 0x83, 0x83, 0x18, 0xe3, 0x36, 0x1a, 0xdb, 0x95, 0xc9, 0x14, 0x9e, 0x87,
0x4b, 0x65, 0x1d, 0xeb, 0x76, 0x99, 0x93, 0x5a, 0x91, 0xa5, 0x00, 0xdb, 0xbe, 0xe2, 0x77, 0xe1, 0xdc, 0xa2, 0xbb, 0xb0, 0x9d, 0x30, 0x69, 0xbc, 0x54, 0xd6, 0xb1, 0x28, 0x62, 0x4e, 0x6a, 0x45,
0x1f, 0xe9, 0x1b, 0x38, 0x36, 0xf8, 0x35, 0x41, 0xeb, 0x3c, 0x13, 0xc2, 0xa0, 0xb5, 0xfe, 0xb3, 0x56, 0x02, 0x6c, 0x07, 0x8a, 0x7f, 0x0c, 0x7f, 0x43, 0x1f, 0xc0, 0x89, 0xc1, 0x17, 0x29, 0x5a,
0x36, 0xde, 0x19, 0xa6, 0x2c, 0xe3, 0x99, 0x68, 0x99, 0x7e, 0x84, 0x77, 0x8c, 0x73, 0x8c, 0x9d, 0xe7, 0x99, 0x10, 0x06, 0xad, 0xf5, 0x67, 0xda, 0x78, 0x67, 0x98, 0xb2, 0x8c, 0xe7, 0xa2, 0x55,
0x7f, 0x4a, 0xbb, 0x42, 0x3f, 0xc1, 0x7b, 0x81, 0xbc, 0x2b, 0x15, 0x3e, 0x29, 0x7e, 0x41, 0x77, 0xfa, 0x14, 0x1e, 0x31, 0xce, 0x31, 0x71, 0xfe, 0x6b, 0xda, 0x35, 0xfa, 0x0c, 0x1e, 0x0b, 0xe4,
0xe1, 0xd5, 0x54, 0x34, 0x4f, 0xac, 0xd2, 0x2d, 0x20, 0x16, 0x95, 0xb8, 0x83, 0x02, 0x3d, 0x86, 0x91, 0x54, 0xf8, 0x55, 0xf1, 0x6d, 0xba, 0x0f, 0xf7, 0x66, 0xa2, 0x45, 0x62, 0x9d, 0xee, 0x00,
0xfd, 0xfb, 0xb1, 0xe7, 0x05, 0xe5, 0x60, 0xcd, 0x83, 0x22, 0xfd, 0xc4, 0x40, 0xb2, 0xb6, 0x98, 0xb1, 0xa8, 0xc4, 0x47, 0x28, 0xd0, 0x13, 0x38, 0xfa, 0xf4, 0xee, 0x45, 0xc1, 0x46, 0xb0, 0xe6,
0x66, 0x9c, 0xeb, 0x44, 0x39, 0xb2, 0x4e, 0x5f, 0xc3, 0xe1, 0x43, 0x3a, 0x4e, 0x9a, 0x5d, 0xc9, 0x5a, 0x91, 0x7e, 0x6a, 0x20, 0xd9, 0x5c, 0x4e, 0x33, 0xce, 0x75, 0xaa, 0x1c, 0xb9, 0x43, 0xef,
0x7d, 0xe8, 0x0b, 0xd9, 0xa0, 0x47, 0x50, 0x9d, 0xf6, 0x83, 0x6b, 0x81, 0x9e, 0x89, 0x1e, 0x1a, 0x43, 0xed, 0x3a, 0x9d, 0xa4, 0xed, 0x48, 0x72, 0x1f, 0xfa, 0x42, 0xb6, 0x68, 0x1d, 0x0e, 0x67,
0x27, 0x2d, 0x46, 0xa8, 0x1c, 0x79, 0x49, 0xeb, 0x70, 0x14, 0x27, 0xb6, 0xed, 0x95, 0x76, 0xf2, 0xfd, 0xe0, 0x5a, 0xa0, 0x67, 0xa2, 0x8f, 0xc6, 0x49, 0x8b, 0x31, 0x2a, 0x47, 0xee, 0xd2, 0x26,
0xb3, 0xe4, 0x79, 0x08, 0x83, 0x2d, 0x69, 0x9d, 0xc9, 0x2d, 0x27, 0xc1, 0xa1, 0xff, 0xd7, 0x78, 0xd4, 0x93, 0xd4, 0x76, 0xbd, 0xd2, 0x4e, 0x9e, 0x49, 0x5e, 0x5c, 0x61, 0xb0, 0x23, 0xad, 0x33,
0x83, 0x36, 0xd6, 0xca, 0x22, 0xd9, 0xa4, 0xfb, 0xb0, 0xfb, 0x50, 0xfc, 0x35, 0x41, 0xd3, 0x27, 0x85, 0xe5, 0x24, 0x38, 0xf4, 0x65, 0x8d, 0x37, 0x68, 0x13, 0xad, 0x2c, 0x92, 0x6d, 0x7a, 0x04,
0x94, 0xbe, 0x85, 0xda, 0x23, 0x64, 0x11, 0xe2, 0x55, 0xa8, 0x7a, 0x51, 0xbe, 0xcc, 0x3f, 0xb2, 0xfb, 0xd7, 0xc5, 0x2f, 0x52, 0x34, 0x03, 0x42, 0xe9, 0x43, 0x68, 0x7c, 0x86, 0x2c, 0xaf, 0xb8,
0x15, 0x4a, 0x5a, 0x44, 0x4f, 0xae, 0x6f, 0x87, 0x11, 0xc4, 0x48, 0x7f, 0x91, 0xde, 0xe0, 0xc4, 0x17, 0xaa, 0x5e, 0x96, 0x2f, 0xf7, 0x8f, 0xec, 0x84, 0x92, 0x96, 0xd1, 0xd3, 0xf0, 0xdd, 0x30,
0xe7, 0x1d, 0xba, 0x07, 0xdb, 0x2d, 0xa3, 0x93, 0x38, 0xb3, 0xc5, 0x4b, 0xd5, 0x93, 0x2e, 0xaf, 0x82, 0x18, 0xeb, 0xe7, 0xd2, 0x1b, 0x9c, 0xfa, 0xbc, 0x47, 0x0f, 0x60, 0xb7, 0x63, 0x74, 0x9a,
0x6e, 0x97, 0x6e, 0xc2, 0x7a, 0x0e, 0x0a, 0x54, 0x4e, 0xba, 0x3e, 0xa9, 0x04, 0x35, 0xd7, 0x51, 0xe4, 0xb6, 0x78, 0xa9, 0xfa, 0xd2, 0x15, 0xd5, 0xed, 0xd3, 0x6d, 0xb8, 0x53, 0x80, 0x02, 0x95,
0x94, 0x28, 0xe9, 0xfa, 0x5e, 0xa0, 0xe5, 0x46, 0xc6, 0x99, 0x7a, 0x8f, 0x56, 0x60, 0xab, 0xa0, 0x93, 0x6e, 0x40, 0xaa, 0x41, 0xcd, 0x75, 0x1c, 0xa7, 0x4a, 0xba, 0x81, 0x17, 0x68, 0xb9, 0x91,
0xe6, 0xe2, 0x54, 0xc3, 0xab, 0x0b, 0x66, 0xd6, 0x6d, 0xed, 0xbf, 0x68, 0xa9, 0xc8, 0x3e, 0x7d, 0x49, 0xae, 0x3e, 0xa0, 0x55, 0xd8, 0x29, 0xa9, 0x85, 0x7b, 0x0e, 0xc3, 0xab, 0x4b, 0x66, 0xde,
0x09, 0xe5, 0x58, 0xaa, 0xd9, 0xd8, 0x1f, 0x84, 0xdd, 0x41, 0x21, 0x8b, 0xdd, 0x39, 0x0c, 0x2f, 0x6d, 0xed, 0x9f, 0x6b, 0xa9, 0xc8, 0x11, 0xbd, 0x0b, 0x1b, 0x89, 0x54, 0xf3, 0xb1, 0x3f, 0x0e,
0xb1, 0x8e, 0xb9, 0xc4, 0x4e, 0x57, 0xe7, 0x28, 0xd4, 0x22, 0xb0, 0x8b, 0x73, 0xfb, 0x72, 0x1c, 0xbb, 0x83, 0x42, 0x96, 0xbb, 0x53, 0x0b, 0x2f, 0xb1, 0x8e, 0xb9, 0xd4, 0xce, 0x56, 0xa7, 0x1e,
0x86, 0x6a, 0xd1, 0xcc, 0x4c, 0x52, 0x93, 0x1a, 0xad, 0xc2, 0x0e, 0x53, 0x5a, 0xf5, 0x23, 0x9d, 0x6a, 0x11, 0x18, 0xe1, 0xc2, 0xbe, 0x9c, 0x84, 0xa1, 0x5a, 0x36, 0x33, 0xd3, 0xd4, 0xa4, 0x41,
0x58, 0x1f, 0xa1, 0x33, 0x92, 0xfb, 0x26, 0x73, 0xbc, 0x4d, 0x5e, 0xcf, 0xb6, 0x2a, 0x2b, 0xd9, 0x0f, 0x61, 0x8f, 0x29, 0xad, 0x06, 0xb1, 0x4e, 0xad, 0x8f, 0xd1, 0x19, 0xc9, 0x7d, 0x9b, 0x39,
0x60, 0xa4, 0x7b, 0x28, 0x48, 0x3d, 0x74, 0xad, 0x80, 0x27, 0xa9, 0x6c, 0x30, 0x50, 0x90, 0x37, 0xde, 0x25, 0xf7, 0xe7, 0x5b, 0x95, 0x97, 0x6c, 0x30, 0xd6, 0x7d, 0x14, 0xa4, 0x19, 0xba, 0x56,
0x14, 0x60, 0xb9, 0xc9, 0x78, 0x27, 0x89, 0xc9, 0xdb, 0xd9, 0x44, 0x06, 0x67, 0x7b, 0xa1, 0x52, 0xc2, 0xd3, 0x54, 0x36, 0x18, 0x28, 0xc8, 0x03, 0x0a, 0xb0, 0xda, 0x66, 0xbc, 0x97, 0x26, 0xe4,
0x8e, 0xca, 0xa1, 0xc9, 0xa5, 0x3f, 0xcd, 0x26, 0xf2, 0x3e, 0x9d, 0x6f, 0x23, 0x0a, 0xf2, 0x2e, 0xe1, 0x7c, 0x22, 0x83, 0xb3, 0xfd, 0x50, 0x29, 0x47, 0xe5, 0xd0, 0x14, 0xd2, 0x6f, 0xe7, 0x13,
0x4c, 0xdc, 0x42, 0x89, 0x90, 0x36, 0x92, 0xd6, 0xa2, 0x20, 0xef, 0x33, 0x27, 0x82, 0xa6, 0xa9, 0xf9, 0x29, 0x5d, 0x6c, 0x23, 0x0a, 0xf2, 0x28, 0x4c, 0xdc, 0x52, 0x89, 0x90, 0x36, 0x96, 0xd6,
0x75, 0x27, 0x62, 0xa6, 0x43, 0x4e, 0xe8, 0x0e, 0xd0, 0xfc, 0x85, 0x5d, 0x64, 0xc6, 0xb7, 0xa5, 0xa2, 0x20, 0x8f, 0x73, 0x27, 0x82, 0xa6, 0xad, 0x75, 0x2f, 0x66, 0xa6, 0x47, 0x4e, 0xe9, 0x1e,
0x75, 0xda, 0xf4, 0xc9, 0x87, 0x60, 0x63, 0x86, 0x5b, 0x74, 0x4e, 0xaa, 0x16, 0xf9, 0x48, 0x6b, 0xd0, 0xe2, 0x85, 0x11, 0x32, 0xe3, 0xbb, 0xd2, 0x3a, 0x6d, 0x06, 0xe4, 0x49, 0xb0, 0x31, 0xc7,
0x70, 0x50, 0x34, 0x82, 0x19, 0xde, 0x96, 0x3d, 0xf4, 0x11, 0x6b, 0x29, 0x74, 0x5d, 0xa9, 0x3a, 0x2d, 0x3a, 0x27, 0x55, 0x87, 0x3c, 0xa5, 0x0d, 0x38, 0x2e, 0x1b, 0xc1, 0x0c, 0xef, 0xca, 0x3e,
0xe4, 0x53, 0x73, 0xfd, 0xcf, 0x72, 0xe3, 0xe7, 0xdf, 0xa6, 0x5f, 0xc0, 0x6f, 0xcb, 0xd9, 0xbf, 0xfa, 0x98, 0x75, 0x14, 0xba, 0x48, 0xaa, 0x1e, 0x79, 0x16, 0x9a, 0x98, 0xc7, 0x24, 0x46, 0x9f,
0x5f, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xb9, 0x43, 0x6c, 0x84, 0xa8, 0x05, 0x00, 0x00, 0xc9, 0x08, 0x7d, 0x22, 0xb9, 0x4b, 0x0d, 0x92, 0xef, 0xda, 0xb5, 0x3f, 0xaf, 0xea, 0x95, 0xbf,
0xae, 0xea, 0x95, 0xbf, 0xaf, 0xea, 0x95, 0x3f, 0xfe, 0xa9, 0xdf, 0xf8, 0x75, 0xa3, 0xf5, 0xfd,
0x4f, 0xb3, 0x6f, 0xe5, 0xcb, 0xd5, 0xfc, 0xdf, 0x8f, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0xd8,
0x58, 0xf8, 0x50, 0xd2, 0x05, 0x00, 0x00,
} }
func (m *ApplicationMetadataMessage) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ApplicationMetadataMessage) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *ApplicationMetadataMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.XXX_unrecognized != nil {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.Type != 0 {
i = encodeVarintApplicationMetadataMessage(dAtA, i, uint64(m.Type))
i--
dAtA[i] = 0x18
}
if len(m.Payload) > 0 {
i -= len(m.Payload)
copy(dAtA[i:], m.Payload)
i = encodeVarintApplicationMetadataMessage(dAtA, i, uint64(len(m.Payload)))
i--
dAtA[i] = 0x12
}
if len(m.Signature) > 0 {
i -= len(m.Signature)
copy(dAtA[i:], m.Signature)
i = encodeVarintApplicationMetadataMessage(dAtA, i, uint64(len(m.Signature)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintApplicationMetadataMessage(dAtA []byte, offset int, v uint64) int {
offset -= sovApplicationMetadataMessage(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *ApplicationMetadataMessage) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Signature)
if l > 0 {
n += 1 + l + sovApplicationMetadataMessage(uint64(l))
}
l = len(m.Payload)
if l > 0 {
n += 1 + l + sovApplicationMetadataMessage(uint64(l))
}
if m.Type != 0 {
n += 1 + sovApplicationMetadataMessage(uint64(m.Type))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovApplicationMetadataMessage(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozApplicationMetadataMessage(x uint64) (n int) {
return sovApplicationMetadataMessage(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *ApplicationMetadataMessage) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApplicationMetadataMessage
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ApplicationMetadataMessage: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ApplicationMetadataMessage: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApplicationMetadataMessage
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthApplicationMetadataMessage
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthApplicationMetadataMessage
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...)
if m.Signature == nil {
m.Signature = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Payload", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApplicationMetadataMessage
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthApplicationMetadataMessage
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthApplicationMetadataMessage
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Payload = append(m.Payload[:0], dAtA[iNdEx:postIndex]...)
if m.Payload == nil {
m.Payload = []byte{}
}
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
}
m.Type = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApplicationMetadataMessage
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Type |= ApplicationMetadataMessage_Type(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipApplicationMetadataMessage(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthApplicationMetadataMessage
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipApplicationMetadataMessage(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApplicationMetadataMessage
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApplicationMetadataMessage
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApplicationMetadataMessage
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthApplicationMetadataMessage
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupApplicationMetadataMessage
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthApplicationMetadataMessage
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthApplicationMetadataMessage = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowApplicationMetadataMessage = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupApplicationMetadataMessage = fmt.Errorf("proto: unexpected end of group")
)

View File

@ -57,5 +57,6 @@ message ApplicationMetadataMessage {
SYNC_CLEAR_HISTORY = 41; SYNC_CLEAR_HISTORY = 41;
SYNC_SETTING = 42; SYNC_SETTING = 42;
COMMUNITY_ARCHIVE_MAGNETLINK = 43; COMMUNITY_ARCHIVE_MAGNETLINK = 43;
SYNC_PROFILE_PICTURE = 44;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -119,3 +119,18 @@ message SyncClearHistory {
string chat_id = 1; string chat_id = 1;
uint64 cleared_at = 2; uint64 cleared_at = 2;
} }
message SyncProfilePicture {
string name = 1;
bytes payload = 2;
uint32 width = 3;
uint32 height = 4;
uint32 file_size = 5;
uint32 resize_target = 6;
uint64 clock = 7;
}
message SyncProfilePictures {
string key_uid = 1;
repeated SyncProfilePicture pictures = 2;
}

View File

@ -209,6 +209,9 @@ func (m *StatusMessage) HandleApplication() error {
case protobuf.ApplicationMetadataMessage_SYNC_INSTALLATION_ACCOUNT: case protobuf.ApplicationMetadataMessage_SYNC_INSTALLATION_ACCOUNT:
return m.unmarshalProtobufData(new(protobuf.SyncInstallationAccount)) return m.unmarshalProtobufData(new(protobuf.SyncInstallationAccount))
case protobuf.ApplicationMetadataMessage_SYNC_PROFILE_PICTURE:
return m.unmarshalProtobufData(new(protobuf.SyncProfilePictures))
case protobuf.ApplicationMetadataMessage_PAIR_INSTALLATION: case protobuf.ApplicationMetadataMessage_PAIR_INSTALLATION:
return m.unmarshalProtobufData(new(protobuf.PairInstallation)) return m.unmarshalProtobufData(new(protobuf.PairInstallation))

View File

@ -49,7 +49,7 @@ func (api *MultiAccountsAPI) StoreIdentityImage(keyUID, filepath string, aX, aY,
return nil, err return nil, err
} }
err = api.db.StoreIdentityImages(keyUID, iis) err = api.db.StoreIdentityImages(keyUID, iis, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -63,7 +63,7 @@ func (api *MultiAccountsAPI) StoreIdentityImageFromURL(keyUID, url string) ([]*i
return nil, err return nil, err
} }
err = api.db.StoreIdentityImages(keyUID, iis) err = api.db.StoreIdentityImages(keyUID, iis, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }