示例#1
0
        private async Task HandleSessionResetMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp)
        {
            SignalMessageDirection type;
            SignalContact          author;
            SignalMessageStatus    status;
            SignalConversation     conversation;
            string prefix;
            string conversationId;
            long   composedTimestamp;

            if (isSync)
            {
                var sent = content.SynchronizeMessage.Sent;
                type              = SignalMessageDirection.Synced;
                status            = SignalMessageStatus.Confirmed;
                composedTimestamp = sent.Timestamp;
                author            = null;
                prefix            = "You have";
                conversationId    = sent.Destination.ForceGetValue();
            }
            else
            {
                status = 0;
                type   = SignalMessageDirection.Incoming;
                author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), timestamp);

                prefix            = $"{author.ThreadDisplayName} has";
                composedTimestamp = envelope.GetTimestamp();
                conversationId    = envelope.GetSource();
            }
            LibsignalDBContext.DeleteAllSessions(conversationId);
            conversation = await SignalDBContext.GetOrCreateContactLocked(conversationId, 0);

            SignalMessage sm = new SignalMessage()
            {
                Direction = type,
                Type      = SignalMessageType.SessionReset,
                Status    = status,
                Author    = author,
                Content   = new SignalMessageContent()
                {
                    Content = $"{prefix} reset the session."
                },
                ThreadId          = conversationId,
                DeviceId          = (uint)envelope.GetSourceDevice(),
                Receipts          = 0,
                ComposedTimestamp = composedTimestamp,
                ReceivedTimestamp = timestamp,
            };
            await SignalLibHandle.Instance.SaveAndDispatchSignalMessage(sm, null, conversation);
        }
示例#2
0
        private byte[] Decrypt(SignalServiceEnvelope envelope, byte[] ciphertext)

        {
            SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.GetSource(), (uint)envelope.GetSourceDevice());
            SessionCipher         sessionCipher = new SessionCipher(SignalProtocolStore, sourceAddress);

            byte[] paddedMessage;

            if (envelope.IsPreKeySignalMessage())
            {
                paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
            }
            else if (envelope.IsSignalMessage())
            {
                paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
            }
            else
            {
                throw new InvalidMessageException("Unknown type: " + envelope.GetEnvelopeType() + " from " + envelope.GetSource());
            }

            PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());

            return(transportDetails.GetStrippedPaddingMessageBody(paddedMessage));
        }
示例#3
0
        private async Task HandleSignalMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp)
        {
            SignalMessageDirection type;
            SignalContact          author;
            SignalMessageStatus    status;
            SignalConversation     conversation;
            long   composedTimestamp;
            string body = dataMessage.Body ?? "";

            if (dataMessage.Group != null)
            {
                var rawId    = dataMessage.Group.GroupId;
                var threadId = Base64.EncodeBytes(rawId);
                conversation = await SignalDBContext.GetOrCreateGroupLocked(threadId, timestamp);

                if (!conversation.CanReceive)
                {
                    SignalServiceGroup group = new SignalServiceGroup()
                    {
                        Type    = SignalServiceGroup.GroupType.REQUEST_INFO,
                        GroupId = rawId
                    };
                    SignalServiceDataMessage requestInfoMessage = new SignalServiceDataMessage()
                    {
                        Group     = group,
                        Timestamp = Util.CurrentTimeMillis()
                    };
                    SignalLibHandle.Instance.OutgoingQueue.Add(new SignalServiceDataMessageSendable(requestInfoMessage, envelope.GetSourceAddress()));
                }
                composedTimestamp = envelope.GetTimestamp();
            }
            else
            {
                if (isSync)
                {
                    var sent = content.SynchronizeMessage.Sent;
                    conversation = await SignalDBContext.GetOrCreateContactLocked(sent.Destination.ForceGetValue(), timestamp);

                    composedTimestamp = sent.Timestamp;
                }
                else
                {
                    conversation = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), timestamp);

                    composedTimestamp = envelope.GetTimestamp();
                }
            }

            if (isSync)
            {
                type   = SignalMessageDirection.Synced;
                status = SignalMessageStatus.Confirmed;
                author = null;
            }
            else
            {
                status = 0;
                type   = SignalMessageDirection.Incoming;
                author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), timestamp);
            }

            if (author != null && author.Blocked)
            {
                // Don't save blocked messages
                return;
            }

            List <SignalAttachment> attachments = new List <SignalAttachment>();
            SignalMessage           message     = new SignalMessage()
            {
                Direction = type,
                Status    = status,
                Author    = author,
                Content   = new SignalMessageContent()
                {
                    Content = body.Truncate(2000)
                },
                ThreadId          = conversation.ThreadId,
                DeviceId          = (uint)envelope.GetSourceDevice(),
                Receipts          = 0,
                ComposedTimestamp = composedTimestamp,
                ReceivedTimestamp = timestamp,
                AttachmentsCount  = (uint)attachments.Count,
                Attachments       = attachments
            };

            if (dataMessage.Attachments != null)
            {
                var receivedAttachments = dataMessage.Attachments;
                foreach (var receivedAttachment in receivedAttachments)
                {
                    var pointer         = receivedAttachment.AsPointer();
                    SignalAttachment sa = new SignalAttachment()
                    {
                        Message      = message,
                        Status       = (uint)SignalAttachmentStatus.Default,
                        SentFileName = pointer.FileName,
                        ContentType  = receivedAttachment.ContentType,
                        Key          = pointer.Key,
                        Relay        = pointer.Relay,
                        StorageId    = pointer.Id,
                        Size         = (long)pointer.Size,
                        Digest       = pointer.Digest
                    };
                    attachments.Add(sa);
                }

                // Make sure to update attachments count
                message.AttachmentsCount = (uint)attachments.Count;
            }
            await SignalLibHandle.Instance.SaveAndDispatchSignalMessage(message, null, conversation);
        }
示例#4
0
        private async Task HandleGroupUpdateMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp)
        {
            if (dataMessage.Group != null) //TODO check signal droid: group messages have different types!
            {
                SignalServiceGroup group       = dataMessage.Group;
                string             groupid     = Base64.EncodeBytes(group.GroupId);
                SignalGroup        g           = new SignalGroup();
                string             displayname = "Unknown group";
                string             avatarfile  = null;
                if (group.Name != null)
                {
                    displayname = group.Name;
                }
                var dbgroup = SignalDBContext.InsertOrUpdateGroupLocked(groupid, displayname, avatarfile, true, timestamp);
                if (group.Members != null)
                {
                    foreach (var member in group.Members)
                    {
                        SignalDBContext.InsertOrUpdateGroupMembershipLocked(dbgroup.Id, (await SignalDBContext.GetOrCreateContactLocked(member, 0)).Id);
                    }
                }

                /* insert message into conversation */
                SignalMessageDirection type;
                SignalContact          author;
                SignalMessageStatus    status;
                string prefix;
                long   composedTimestamp;

                if (isSync)
                {
                    var sent = content.SynchronizeMessage.Sent;
                    type              = SignalMessageDirection.Synced;
                    status            = SignalMessageStatus.Confirmed;
                    composedTimestamp = sent.Timestamp;
                    author            = null;
                    prefix            = "You have";
                }
                else
                {
                    status = 0;
                    type   = SignalMessageDirection.Incoming;
                    author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), timestamp);

                    prefix            = $"{author.ThreadDisplayName} has";
                    composedTimestamp = envelope.GetTimestamp();
                }

                SignalMessage sm = new SignalMessage()
                {
                    Direction = type,
                    Type      = SignalMessageType.GroupUpdate,
                    Status    = status,
                    Author    = author,
                    Content   = new SignalMessageContent()
                    {
                        Content = $"{prefix} updated the group."
                    },
                    ThreadId          = groupid,
                    DeviceId          = (uint)envelope.GetSourceDevice(),
                    Receipts          = 0,
                    ComposedTimestamp = composedTimestamp,
                    ReceivedTimestamp = timestamp,
                };
                SignalDBContext.SaveMessageLocked(sm);
                dbgroup.MessagesCount += 1;
                if (sm.Direction == SignalMessageDirection.Incoming)
                {
                    dbgroup.UnreadCount += 1;
                }
                else
                {
                    dbgroup.UnreadCount          = 0;
                    dbgroup.LastSeenMessageIndex = dbgroup.MessagesCount;
                }
                dbgroup.LastMessage = sm;
                await SignalLibHandle.Instance.DispatchAddOrUpdateConversation(dbgroup, sm);
            }
            else
            {
                Logger.LogError("HandleGroupUpdateMessage() received group update without group info");
            }
        }
示例#5
0
        private async Task HandleGroupLeaveMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage dataMessage, bool isSync, long timestamp)
        {
            SignalServiceGroup sentGroup = dataMessage.Group;

            if (sentGroup != null)
            {
                string      groupid = Base64.EncodeBytes(sentGroup.GroupId);
                SignalGroup group   = await SignalDBContext.GetOrCreateGroupLocked(groupid, 0);

                if (isSync)
                {
                    SignalContact author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), 0);

                    SignalMessage sm = new SignalMessage()
                    {
                        Direction = SignalMessageDirection.Incoming,
                        Type      = SignalMessageType.GroupLeave,
                        Status    = SignalMessageStatus.Received,
                        Author    = author,
                        Content   = new SignalMessageContent()
                        {
                            Content = $"You have left the group."
                        },
                        ThreadId          = groupid,
                        DeviceId          = (uint)envelope.GetSourceDevice(),
                        Receipts          = 0,
                        ComposedTimestamp = envelope.GetTimestamp(),
                        ReceivedTimestamp = timestamp,
                    };
                    SignalConversation updatedConversation = SignalDBContext.RemoveMemberFromGroup(groupid, author, sm);
                    await SignalLibHandle.Instance.DispatchAddOrUpdateConversation(updatedConversation, sm);
                }
                else
                {
                    SignalContact author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), 0);

                    SignalMessage sm = new SignalMessage()
                    {
                        Direction = SignalMessageDirection.Incoming,
                        Type      = SignalMessageType.GroupLeave,
                        Status    = SignalMessageStatus.Received,
                        Author    = author,
                        Content   = new SignalMessageContent()
                        {
                            Content = $"{author.ThreadDisplayName} has left the group."
                        },
                        ThreadId          = groupid,
                        DeviceId          = (uint)envelope.GetSourceDevice(),
                        Receipts          = 0,
                        ComposedTimestamp = envelope.GetTimestamp(),
                        ReceivedTimestamp = timestamp,
                    };
                    SignalConversation updatedConversation = SignalDBContext.RemoveMemberFromGroup(groupid, author, sm);
                    await SignalLibHandle.Instance.DispatchAddOrUpdateConversation(updatedConversation, sm);
                }
            }
            else
            {
                Logger.LogError("HandleGroupLeaveMessage() received group update without group info");
            }
        }
示例#6
0
        private async Task HandleExpirationUpdateMessage(SignalServiceEnvelope envelope, SignalServiceContent content, SignalServiceDataMessage message, bool isSync, long timestamp)
        {
            SignalMessageDirection type;
            SignalContact          author;
            SignalMessageStatus    status;
            string             prefix;
            SignalConversation conversation;
            long composedTimestamp;

            if (isSync)
            {
                var sent = content.SynchronizeMessage.Sent;
                type              = SignalMessageDirection.Synced;
                status            = SignalMessageStatus.Confirmed;
                composedTimestamp = sent.Timestamp;
                author            = null;
                prefix            = "You have";
                if (message.Group != null)
                {
                    conversation = await SignalDBContext.GetOrCreateGroupLocked(Base64.EncodeBytes(message.Group.GroupId), 0);
                }
                else
                {
                    conversation = await SignalDBContext.GetOrCreateContactLocked(sent.Destination.ForceGetValue(), 0);
                }
            }
            else
            {
                status = 0;
                type   = SignalMessageDirection.Incoming;
                author = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), timestamp);

                prefix            = $"{author.ThreadDisplayName} has";
                composedTimestamp = envelope.GetTimestamp();
                if (message.Group != null)
                {
                    conversation = await SignalDBContext.GetOrCreateGroupLocked(Base64.EncodeBytes(message.Group.GroupId), 0);
                }
                else
                {
                    conversation = await SignalDBContext.GetOrCreateContactLocked(envelope.GetSource(), 0);
                }
            }
            conversation.ExpiresInSeconds = (uint)message.ExpiresInSeconds;
            SignalDBContext.UpdateExpiresInLocked(conversation);
            SignalMessage sm = new SignalMessage()
            {
                Direction = type,
                Type      = SignalMessageType.ExpireUpdate,
                Status    = status,
                Author    = author,
                Content   = new SignalMessageContent()
                {
                    Content = $"{prefix} set the expiration timer to {message.ExpiresInSeconds} seconds."
                },
                ThreadId          = conversation.ThreadId,
                DeviceId          = (uint)envelope.GetSourceDevice(),
                Receipts          = 0,
                ComposedTimestamp = composedTimestamp,
                ReceivedTimestamp = timestamp,
            };
            await SignalLibHandle.Instance.SaveAndDispatchSignalMessage(sm, null, conversation);
        }
示例#7
0
        private Plaintext Decrypt(SignalServiceEnvelope envelope, byte[] ciphertext)
        {
            try
            {
                SignalProtocolAddress sourceAddress       = new SignalProtocolAddress(envelope.GetSource(), (uint)envelope.GetSourceDevice());
                SessionCipher         sessionCipher       = new SessionCipher(SignalProtocolStore, sourceAddress);
                SealedSessionCipher   sealedSessionCipher = new SealedSessionCipher(SignalProtocolStore, new SignalProtocolAddress(LocalAddress.E164number, 1));

                byte[]   paddedMessage;
                Metadata metadata;
                uint     sessionVersion;

                if (envelope.IsPreKeySignalMessage())
                {
                    paddedMessage  = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
                    metadata       = new Metadata(envelope.GetSource(), envelope.GetSourceDevice(), envelope.GetTimestamp(), false);
                    sessionVersion = sessionCipher.getSessionVersion();
                }
                else if (envelope.IsSignalMessage())
                {
                    paddedMessage  = sessionCipher.decrypt(new SignalMessage(ciphertext));
                    metadata       = new Metadata(envelope.GetSource(), envelope.GetSourceDevice(), envelope.GetTimestamp(), false);
                    sessionVersion = sessionCipher.getSessionVersion();
                }
                else if (envelope.IsUnidentifiedSender())
                {
                    var results = sealedSessionCipher.Decrypt(CertificateValidator, ciphertext, (long)envelope.Envelope.ServerTimestamp);
                    paddedMessage  = results.Item2;
                    metadata       = new Metadata(results.Item1.Name, (int)results.Item1.DeviceId, (long)envelope.Envelope.Timestamp, true);
                    sessionVersion = (uint)sealedSessionCipher.GetSessionVersion(new SignalProtocolAddress(metadata.Sender, (uint)metadata.SenderDevice));
                }
                else
                {
                    throw new InvalidMessageException("Unknown type: " + envelope.GetEnvelopeType() + " from " + envelope.GetSource());
                }

                PushTransportDetails transportDetails = new PushTransportDetails(sessionVersion);
                byte[] data = transportDetails.GetStrippedPaddingMessageBody(paddedMessage);
                return(new Plaintext(metadata, data));
            }
            catch (DuplicateMessageException e)
            {
                throw new ProtocolDuplicateMessageException(e, envelope.GetSource(), envelope.GetSourceDevice());
            }
            catch (LegacyMessageException e)
            {
                throw new ProtocolLegacyMessageException(e, envelope.GetSource(), envelope.GetSourceDevice());
            }
            catch (InvalidMessageException e)
            {
                throw new ProtocolInvalidMessageException(e, envelope.GetSource(), envelope.GetSourceDevice());
            }
            catch (InvalidKeyIdException e)
            {
                throw new ProtocolInvalidKeyIdException(e, envelope.GetSource(), envelope.GetSourceDevice());
            }
            catch (InvalidKeyException e)
            {
                throw new ProtocolInvalidKeyException(e, envelope.GetSource(), envelope.GetSourceDevice());
            }
            catch (libsignal.exceptions.UntrustedIdentityException e)
            {
                throw new ProtocolUntrustedIdentityException(e, envelope.GetSource(), envelope.GetSourceDevice());
            }
            catch (InvalidVersionException e)
            {
                throw new ProtocolInvalidVersionException(e, envelope.GetSource(), envelope.GetSourceDevice());
            }
            catch (NoSessionException e)
            {
                throw new ProtocolNoSessionException(e, envelope.GetSource(), envelope.GetSourceDevice());
            }
        }
示例#8
0
        /// <summary>
        /// Decrypt a received <see cref="SignalServiceEnvelope"/>
        /// </summary>
        /// <param name="envelope">The received SignalServiceEnvelope</param>
        /// <returns>a decrypted SignalServiceContent</returns>
        public SignalServiceContent Decrypt(SignalServiceEnvelope envelope)
        {
            try
            {
                SignalServiceContent content = new SignalServiceContent();

                if (envelope.HasLegacyMessage())
                {
                    DataMessage message = DataMessage.Parser.ParseFrom(Decrypt(envelope, envelope.GetLegacyMessage()));
                    content = new SignalServiceContent()
                    {
                        Message = CreateSignalServiceMessage(envelope, message)
                    };
                }
                else if (envelope.HasContent())
                {
                    Content message = Content.Parser.ParseFrom(Decrypt(envelope, envelope.GetContent()));

                    if (message.DataMessageOneofCase == Content.DataMessageOneofOneofCase.DataMessage)
                    {
                        content = new SignalServiceContent()
                        {
                            Message = CreateSignalServiceMessage(envelope, message.DataMessage)
                        };
                    }
                    else if (message.SyncMessageOneofCase == Content.SyncMessageOneofOneofCase.SyncMessage && LocalAddress.E164number == envelope.GetSource())
                    {
                        content = new SignalServiceContent()
                        {
                            SynchronizeMessage = CreateSynchronizeMessage(envelope, message.SyncMessage)
                        };
                    }
                    else if (message.CallMessageOneofCase == Content.CallMessageOneofOneofCase.CallMessage)
                    {
                        content = new SignalServiceContent()
                        {
                            CallMessage = CreateCallMessage(message.CallMessage)
                        };
                    }
                    else if (message.ReceiptMessageOneofCase == Content.ReceiptMessageOneofOneofCase.ReceiptMessage)
                    {
                        content = new SignalServiceContent()
                        {
                            ReadMessage = CreateReceiptMessage(envelope, message.ReceiptMessage)
                        };
                    }
                }

                return(content);
            }
            catch (InvalidProtocolBufferException e)
            {
                throw new InvalidMessageException(e);
            }
        }