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); }
/// <summary> /// /// </summary> /// <param name="envelope"></param> /// <param name="ciphertext"></param> /// <returns></returns> /// <exception cref="InvalidMetadataMessageException"></exception> /// <exception cref="InvalidMetadataVersionException"></exception> /// <exception cref="ProtocolDuplicateMessageException"></exception> /// <exception cref="ProtocolUntrustedIdentityException"></exception> /// <exception cref="ProtocolLegacyMessageException"></exception> /// <exception cref="ProtocolInvalidKeyException"></exception> /// <exception cref="ProtocolInvalidVersionException"></exception> /// <exception cref="ProtocolInvalidMessageException"></exception> /// <exception cref="ProtocolInvalidKeyIdException"></exception> /// <exception cref="ProtocolNoSessionException"></exception> /// <exception cref="SelfSendException"></exception> private Plaintext Decrypt(SignalServiceEnvelope envelope, byte[] ciphertext) { try { byte[] paddedMessage; SignalServiceMetadata metadata; uint sessionVersion; if (!envelope.HasSource() && !envelope.IsUnidentifiedSender()) { throw new ProtocolInvalidMessageException(new InvalidMessageException("Non-UD envelope is missing a source!"), null, 0); } if (envelope.IsPreKeySignalMessage()) { SignalProtocolAddress sourceAddress = GetPreferredProtocolAddress(signalProtocolStore, envelope.GetSourceAddress(), envelope.GetSourceDevice()); SessionCipher sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress); paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext)); metadata = new SignalServiceMetadata(envelope.GetSourceAddress(), envelope.GetSourceDevice(), envelope.GetTimestamp(), false); sessionVersion = sessionCipher.getSessionVersion(); } else if (envelope.IsSignalMessage()) { SignalProtocolAddress sourceAddress = GetPreferredProtocolAddress(signalProtocolStore, envelope.GetSourceAddress(), envelope.GetSourceDevice()); SessionCipher sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress); paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext)); metadata = new SignalServiceMetadata(envelope.GetSourceAddress(), envelope.GetSourceDevice(), envelope.GetTimestamp(), false); sessionVersion = sessionCipher.getSessionVersion(); } else if (envelope.IsUnidentifiedSender()) { SealedSessionCipher sealedSessionCipher = new SealedSessionCipher(signalProtocolStore, localAddress.Uuid, localAddress.GetNumber(), 1); DecryptionResult result = sealedSessionCipher.Decrypt(certificateValidator !, ciphertext, (long)envelope.Envelope.ServerTimestamp); SignalServiceAddress resultAddress = new SignalServiceAddress(UuidUtil.Parse(result.SenderUuid), result.SenderE164); SignalProtocolAddress protocolAddress = GetPreferredProtocolAddress(signalProtocolStore, resultAddress, result.DeviceId); paddedMessage = result.PaddedMessage; metadata = new SignalServiceMetadata(resultAddress, result.DeviceId, envelope.GetTimestamp(), true); sessionVersion = (uint)sealedSessionCipher.GetSessionVersion(protocolAddress); } else { throw new InvalidMessageException($"Unknown type: {envelope.GetType()}"); } PushTransportDetails transportDetails = new PushTransportDetails(sessionVersion); byte[] data = transportDetails.GetStrippedPaddingMessageBody(paddedMessage); return(new Plaintext(metadata, data)); } catch (DuplicateMessageException e) { throw new ProtocolDuplicateMessageException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice()); } catch (LegacyMessageException e) { throw new ProtocolLegacyMessageException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice()); } catch (InvalidMessageException e) { throw new ProtocolInvalidMessageException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice()); } catch (InvalidKeyIdException e) { throw new ProtocolInvalidKeyIdException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice()); } catch (InvalidKeyException e) { throw new ProtocolInvalidKeyException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice()); } catch (libsignal.exceptions.UntrustedIdentityException e) { throw new ProtocolUntrustedIdentityException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice()); } catch (InvalidVersionException e) { throw new ProtocolInvalidVersionException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice()); } catch (NoSessionException e) { throw new ProtocolNoSessionException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice()); } }