From a564066c4f858484404f05c0ec6fffc057f82ace Mon Sep 17 00:00:00 2001 From: Samuel Hawksby-Robinson Date: Mon, 9 Nov 2020 15:16:36 +0000 Subject: [PATCH] Added public chat ChatIdentity publish --- images/database_test.go | 12 ++-- images/meta.go | 12 ++-- protocol/messenger.go | 123 ++++++++++++++++++++++++++++++++-------- 3 files changed, 112 insertions(+), 35 deletions(-) diff --git a/images/database_test.go b/images/database_test.go index 7faf284f1..de1517bfe 100644 --- a/images/database_test.go +++ b/images/database_test.go @@ -88,7 +88,7 @@ func setupTestDB(t *testing.T) (Database, func()) { func seedTestDB(t *testing.T, db Database) { iis := []*IdentityImage{ { - Name: smallDimName, + Name: SmallDimName, Payload: testJpegBytes, Width: 80, Height: 80, @@ -96,7 +96,7 @@ func seedTestDB(t *testing.T, db Database) { ResizeTarget: 80, }, { - Name: largeDimName, + Name: LargeDimName, Payload: testPngBytes, Width: 240, Height: 300, @@ -133,11 +133,11 @@ func TestDatabase_GetIdentityImage(t *testing.T) { Expected string }{ { - smallDimName, + SmallDimName, `{"name":"thumbnail","uri":"data:image/jpeg;base64,/9j/2wCEAFA3PEY8MlA=","width":80,"height":80,"file_size":256,"resize_target":80}`, }, { - largeDimName, + LargeDimName, `{"name":"large","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUg=","width":240,"height":300,"file_size":1024,"resize_target":240}`, }, } @@ -157,9 +157,9 @@ func TestDatabase_DeleteIdentityImage(t *testing.T) { defer stop() seedTestDB(t, db) - require.NoError(t, db.DeleteIdentityImage(smallDimName)) + require.NoError(t, db.DeleteIdentityImage(SmallDimName)) - oii, err := db.GetIdentityImage(smallDimName) + oii, err := db.GetIdentityImage(SmallDimName) require.NoError(t, err) require.Empty(t, oii) } diff --git a/images/meta.go b/images/meta.go index 39594d3eb..18f7d0a13 100644 --- a/images/meta.go +++ b/images/meta.go @@ -17,8 +17,8 @@ const ( SmallDim = ResizeDimension(80) LargeDim = ResizeDimension(240) - smallDimName = "thumbnail" - largeDimName = "large" + SmallDimName = "thumbnail" + LargeDimName = "large" ) var ( @@ -40,14 +40,14 @@ var ( // ResizeDimensionToName maps a ResizeDimension to its assigned string name ResizeDimensionToName = map[ResizeDimension]string{ - SmallDim: smallDimName, - LargeDim: largeDimName, + SmallDim: SmallDimName, + LargeDim: LargeDimName, } // NameToResizeDimension maps a string name to its assigned ResizeDimension NameToResizeDimension = map[string]ResizeDimension{ - smallDimName: SmallDim, - largeDimName: LargeDim, + SmallDimName: SmallDim, + LargeDimName: LargeDim, } ) diff --git a/protocol/messenger.go b/protocol/messenger.go index 2fb9d23f1..4393863ff 100644 --- a/protocol/messenger.go +++ b/protocol/messenger.go @@ -484,21 +484,21 @@ func (m *Messenger) handleSendContactCode() error { } // contactCodeAdvertisement attaches a protobuf.ChatIdentity to the given protobuf.ContactCodeAdvertisement, -// if the last time the ChatIdentity was attached was more than 24 hours ago +// if the `shouldPublish` conditions are met func (m *Messenger) handleContactCodeChatIdentity(cca *protobuf.ContactCodeAdvertisement) error { - pubKey := transport.PublicKeyToStr(&m.identity.PublicKey) - lp, err := m.persistence.GetWhenChatIdentityLastPublished(pubKey) + contactCodeTopic := transport.ContactCodeTopic(&m.identity.PublicKey) + shouldPublish, err := m.shouldPublishChatIdentity(contactCodeTopic) if err != nil { return err } - if *lp == 0 || *lp - time.Now().Unix() > 24 * 60 * 60{ - err = m.attachChatIdentity(cca) + if shouldPublish { + cca.ChatIdentity, err = m.createChatIdentity("private-chat") if err != nil { return err } - err := m.persistence.SaveWhenChatIdentityLastPublished(pubKey) + err = m.persistence.SaveWhenChatIdentityLastPublished(contactCodeTopic) if err != nil { return err } @@ -507,34 +507,106 @@ func (m *Messenger) handleContactCodeChatIdentity(cca *protobuf.ContactCodeAdver return nil } -// attachChatIdentity -func (m *Messenger) attachChatIdentity(cca *protobuf.ContactCodeAdvertisement) error { +// handleStandaloneChatIdentity sends a standalone ChatIdentity message to a public channel if the publish criteria is met +func (m *Messenger) handleStandaloneChatIdentity(chat *Chat) error { + if chat.ChatType != ChatTypePublic { + return nil + } + shouldPublishChatIdentity, err := m.shouldPublishChatIdentity(chat.ID) + if err != nil { + return err + } + if !shouldPublishChatIdentity { + return nil + } - idb := userimage.NewDatabase(m.database) - imgs, err := idb.GetIdentityImages() + ci, err := m.createChatIdentity("public-chat") if err != nil { return err } - // Adapt images.IdentityImage to protobuf.IdentityImage - ciis := make(map[string]*protobuf.IdentityImage) - for _, img := range imgs { - ciis[img.Name] = &protobuf.IdentityImage{ - Payload: img.Payload, - SourceType: protobuf.IdentityImage_RAW_PAYLOAD, // TODO add ENS avatar handling to dedicated PR - ImageType: images.ImageType(img.Payload), - } + payload, err := proto.Marshal(ci) + if err != nil { + return err } - cca.ChatIdentity = &protobuf.ChatIdentity{ - Clock: m.transport.GetCurrentTime(), - EnsName: "", // TODO add ENS name handling to dedicate PR - Images: ciis, + rawMessage := common.RawMessage{ + LocalChatID: chat.ID, + MessageType: protobuf.ApplicationMetadataMessage_CHAT_IDENTITY, + Payload: payload, + } + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + _, err = m.processor.SendPublic(ctx, chat.ID, rawMessage) + if err != nil { + return err + } + + err = m.persistence.SaveWhenChatIdentityLastPublished(chat.ID) + if err != nil { + return err } return nil } +// shouldPublishChatIdentity returns true if the last time the ChatIdentity was attached was more than 24 hours ago +func (m *Messenger) shouldPublishChatIdentity(chatId string) (bool, error) { + lp, err := m.persistence.GetWhenChatIdentityLastPublished(chatId) + if err != nil { + return false, err + } + + return *lp == 0 || time.Now().Unix() - *lp > 24 * 60 * 60, nil +} + +// createChatIdentity creates a context based protobuf.ChatIdentity. +// context 'public-chat' will attach only the 'thumbnail' IdentityImage +// contect 'private-chat' will attach all IdentityImage +func (m *Messenger) createChatIdentity(context string) (*protobuf.ChatIdentity, error) { + ci := &protobuf.ChatIdentity{ + Clock: m.transport.GetCurrentTime(), + EnsName: "", // TODO add ENS name handling to dedicate PR + } + + ciis := make(map[string]*protobuf.IdentityImage) + + switch context { + case "public-chat": + idb := userimage.NewDatabase(m.database) + img, err := idb.GetIdentityImage(userimage.SmallDimName) + if err != nil { + return nil, err + } + + ciis[userimage.SmallDimName] = m.adaptIdentityImageToProtobuf(img) + ci.Images = ciis + + case "private-chat": + idb := userimage.NewDatabase(m.database) + imgs, err := idb.GetIdentityImages() + if err != nil { + return nil, err + } + + for _, img := range imgs { + ciis[img.Name] = m.adaptIdentityImageToProtobuf(img) + } + ci.Images = ciis + } + + return ci, nil +} + +// adaptIdentityImageToProtobuf Adapts a images.IdentityImage to protobuf.IdentityImage +func (m *Messenger) adaptIdentityImageToProtobuf(img *userimage.IdentityImage) *protobuf.IdentityImage { + return &protobuf.IdentityImage{ + Payload: img.Payload, + SourceType: protobuf.IdentityImage_RAW_PAYLOAD, // TODO add ENS avatar handling to dedicated PR + ImageType: images.ImageType(img.Payload), + } +} + // handleSharedSecrets process the negotiated secrets received from the encryption layer func (m *Messenger) handleSharedSecrets(secrets []*sharedsecret.Secret) error { var result []*transport.Filter @@ -1984,7 +2056,12 @@ func (m *Messenger) sendChatMessage(ctx context.Context, message *common.Message return nil, errors.New("Chat not found") } - err := extendMessageFromChat(message, chat, &m.identity.PublicKey, m.getTimesource()) + err := m.handleStandaloneChatIdentity(chat) + if err != nil { + return nil, err + } + + err = extendMessageFromChat(message, chat, &m.identity.PublicKey, m.getTimesource()) if err != nil { return nil, err }