diff --git a/model/group.go b/model/group.go index f13b31c..dd59aef 100644 --- a/model/group.go +++ b/model/group.go @@ -104,7 +104,7 @@ func (g *Group) Invite(initialMessage []byte) ([]byte, error) { } // AddMessage takes a DecryptedGroupMessage and adds it to the Groups Timeline -func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, sig []byte) *Message { +func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, sig []byte) (*Message, bool) { timelineMessage := &Message{ Message: message.GetText(), Timestamp: time.Unix(int64(message.GetTimestamp()), 0), @@ -113,8 +113,8 @@ func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, sig []byte) PeerID: message.GetOnion(), PreviousMessageSig: message.GetPreviousMessageSig(), } - g.Timeline.Insert(timelineMessage) - return timelineMessage + seen := g.Timeline.Insert(timelineMessage) + return timelineMessage, seen } // GetTimeline provides a safe copy of the timeline diff --git a/model/message_test.go b/model/message_test.go index 3f1c793..b18239e 100644 --- a/model/message_test.go +++ b/model/message_test.go @@ -80,12 +80,12 @@ func TestTranscriptConsistency(t *testing.T) { c5, s5, _ := alice.EncryptMessageToGroup("Hello World 5", group.GroupID) t.Logf("Length of Encrypted Message: %v", len(c5)) - _, _, m1 := sarah.AttemptDecryption(c1, s1) + _, _, m1, _ := sarah.AttemptDecryption(c1, s1) sarah.AttemptDecryption(c1, s1) // Try a duplicate - _, _, m2 := sarah.AttemptDecryption(c2, s2) - _, _, m3 := sarah.AttemptDecryption(c3, s3) - _, _, m4 := sarah.AttemptDecryption(c4, s4) - _, _, m5 := sarah.AttemptDecryption(c5, s5) + _, _, m2, _ := sarah.AttemptDecryption(c2, s2) + _, _, m3, _ := sarah.AttemptDecryption(c3, s3) + _, _, m4, _ := sarah.AttemptDecryption(c4, s4) + _, _, m5, _ := sarah.AttemptDecryption(c5, s5) // Now we simulate a client receiving these Messages completely out of order timeline.Insert(m1) diff --git a/model/profile.go b/model/profile.go index 5e1a9c7..2dd0f7f 100644 --- a/model/profile.go +++ b/model/profile.go @@ -297,7 +297,7 @@ func (p *Profile) AddGroup(group *Group) { } // AttemptDecryption takes a ciphertext and signature and attempts to decrypt it under known groups. -func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (bool, string, *Message) { +func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (bool, string, *Message, bool) { for _, group := range p.Groups { success, dgm := group.DecryptMessage(ciphertext) if success { @@ -308,14 +308,15 @@ func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (bool, // Either way, someone who has the private key is being detectably bad so we are just going to throw this message away and mark the group as Compromised. if !verified { group.Compromised() - return false, group.GroupID, nil + return false, group.GroupID, nil, false } - return true, group.GroupID, group.AddMessage(dgm, signature) + message, seen := group.AddMessage(dgm, signature) + return true, group.GroupID, message, seen } } // If we couldn't find a group to decrypt the message with we just return false. This is an expected case - return false, "", nil + return false, "", nil, false } func getRandomness(arr *[]byte) { diff --git a/model/profile_test.go b/model/profile_test.go index f3c41de..c056655 100644 --- a/model/profile_test.go +++ b/model/profile_test.go @@ -161,13 +161,13 @@ func TestProfileGroup(t *testing.T) { bob.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion) c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID) if err == nil { - ok, _, message := alice.AttemptDecryption(c3, s3) + ok, _, message, _ := alice.AttemptDecryption(c3, s3) if !ok { t.Errorf("Bobs message to the group should be decrypted %v %v", message, ok) } eve := GenerateNewProfile("eve") - ok, _, _ = eve.AttemptDecryption(c3, s3) + ok, _, _, _ = eve.AttemptDecryption(c3, s3) if ok { t.Errorf("Eves hould not be able to decrypt Messages!") } diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index 27c6e66..f10f240 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -162,7 +162,7 @@ func (cp *cwtchPeer) StartGroupWithMessage(server string, initialMessage []byte) if err == nil { group := cp.GetGroup(groupID) jsobj, err := json.Marshal(group) - if err != nil { + if err == nil { cp.eventBus.Publish(event.NewEvent(event.GroupCreated, map[event.Field]string{ event.Data: string(jsobj), })) @@ -312,10 +312,10 @@ func (cp *cwtchPeer) eventHandler() { ev := cp.queue.Next() switch ev.EventType { case event.EncryptedGroupMessage: - ok, groupID, message := cp.Profile.AttemptDecryption([]byte(ev.Data[event.Ciphertext]), []byte(ev.Data[event.Signature])) + ok, groupID, message, seen := cp.Profile.AttemptDecryption([]byte(ev.Data[event.Ciphertext]), []byte(ev.Data[event.Signature])) log.Debugf("ok,gid,msg = %v,%v,%v", ok, groupID, message) - if ok { - cp.eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{event.TimestampReceived: message.Received.Format(time.RFC3339Nano), event.TimestampSent: message.Timestamp.Format(time.RFC3339Nano), event.Data: message.Message, event.GroupID: groupID, event.RemotePeer: message.PeerID})) + if ok && !seen { + cp.eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{event.TimestampReceived: message.Received.Format(time.RFC3339Nano), event.TimestampSent: message.Timestamp.Format(time.RFC3339Nano), event.Data: message.Message, event.GroupID: groupID, event.Signature: string(message.Signature), event.RemotePeer: message.PeerID})) } case event.NewGroupInvite: var groupInvite protocol.GroupChatInvite diff --git a/storage/profile_store.go b/storage/profile_store.go index cd66c74..a8e1c64 100644 --- a/storage/profile_store.go +++ b/storage/profile_store.go @@ -153,7 +153,7 @@ func (ps *profileStore) eventHandler() { received, _ := time.Parse(time.RFC3339Nano, ev.Data[event.TimestampReceived]) sent, _ := time.Parse(time.RFC3339Nano, ev.Data[event.TimestampSent]) // TODO: Sig, prev message Sig - message := model.Message{Received: received, Timestamp: sent, Message: ev.Data[event.Data], PeerID: ev.Data[event.RemotePeer]} + message := model.Message{Received: received, Timestamp: sent, Message: ev.Data[event.Data], PeerID: ev.Data[event.RemotePeer], Signature: []byte(ev.Data[event.Signature])} //ps.profile.Groups[groupid].AddMessage(message) <- wants protocol.DecryptedGroupMessage so group.Timeline will drift here from launch when it's initialized ps.streamStores[groupid].Write(message) default: