/// <summary> /// /// </summary> /// <param name="metadata"></param> /// <param name="content"></param> /// <returns></returns> /// <exception cref="ProtocolInvalidMessageException"></exception> private static SignalServiceTypingMessage CreateTypingMessage(SignalServiceMetadata metadata, TypingMessage content) { SignalServiceTypingMessage.Action action; if (content.Action == push.TypingMessage.Types.Action.Started) { action = SignalServiceTypingMessage.Action.STARTED; } else if (content.Action == push.TypingMessage.Types.Action.Stopped) { action = SignalServiceTypingMessage.Action.STOPPED; } else { action = SignalServiceTypingMessage.Action.UNKNOWN; } if (content.HasTimestamp && (long)content.Timestamp != metadata.Timestamp) { throw new ProtocolInvalidMessageException(new InvalidMessageException($"Timestamps don't match: {content.Timestamp} vs {metadata.Timestamp}"), metadata.Sender.GetIdentifier(), metadata.SenderDevice); } return(new SignalServiceTypingMessage(action, (long)content.Timestamp, content.HasGroupId ? content.GroupId.ToByteArray() : null)); }
private static SignalServiceDataMessage CreateSignalServiceMessage(SignalServiceMetadata metadata, DataMessage content) { SignalServiceGroup? groupInfo = CreateGroupV1Info(content); List <SignalServiceAttachment> attachments = new List <SignalServiceAttachment>(); bool endSession = ((content.Flags & (uint)DataMessage.Types.Flags.EndSession) != 0); bool expirationUpdate = ((content.Flags & (uint)DataMessage.Types.Flags.ExpirationTimerUpdate) != 0); bool profileKeyUpdate = ((content.Flags & (uint)DataMessage.Types.Flags.ProfileKeyUpdate) != 0); SignalServiceDataMessage.SignalServiceQuote?quote = CreateQuote(content); List <SharedContact>?sharedContacts = CreateSharedContacts(content); List <SignalServiceDataMessage.SignalServicePreview>?previews = CreatePreviews(content); SignalServiceDataMessage.SignalServiceSticker?sticker = CreateSticker(content); if (content.RequiredProtocolVersion > (int)DataMessage.Types.ProtocolVersion.Current) { throw new UnsupportedDataMessageException((int)DataMessage.Types.ProtocolVersion.Current, (int)content.RequiredProtocolVersion, metadata.Sender.GetIdentifier(), metadata.SenderDevice, groupInfo); } foreach (AttachmentPointer pointer in content.Attachments) { attachments.Add(CreateAttachmentPointer(pointer)); } if (content.HasTimestamp && (long)content.Timestamp != metadata.Timestamp) { throw new ProtocolInvalidMessageException(new InvalidMessageException("Timestamps don't match: " + content.Timestamp + " vs " + metadata.Timestamp), metadata.Sender.GetIdentifier(), metadata.SenderDevice); } return(new SignalServiceDataMessage(metadata.Timestamp, groupInfo, attachments, content.Body, endSession, (int)content.ExpireTimer, expirationUpdate, content.HasProfileKey ? content.ProfileKey.ToByteArray() : null, profileKeyUpdate, quote, sharedContacts, previews, sticker, content.IsViewOnce)); }
private static SignalServiceReceiptMessage CreateReceiptMessage(SignalServiceMetadata metadata, ReceiptMessage content) { SignalServiceReceiptMessage.Type type; if (content.Type == ReceiptMessage.Types.Type.Delivery) { type = SignalServiceReceiptMessage.Type.DELIVERY; } else if (content.Type == ReceiptMessage.Types.Type.Read) { type = SignalServiceReceiptMessage.Type.READ; } else { type = SignalServiceReceiptMessage.Type.UNKNOWN; } return(new SignalServiceReceiptMessage() { ReceiptType = type, Timestamps = content.Timestamp.ToList(), When = metadata.Timestamp }); }
/// <summary> /// /// </summary> /// <param name="metadata"></param> /// <param name="content"></param> /// <returns></returns> /// <exception cref="ProtocolInvalidMessageException"></exception> /// <exception cref="ProtocolInvalidKeyException"></exception> private static SignalServiceSyncMessage CreateSynchronizeMessage(SignalServiceMetadata metadata, SyncMessage content) { if (content.Sent != null) { var unidentifiedStatuses = new Dictionary <SignalServiceAddress, bool>(); SyncMessage.Types.Sent sentContent = content.Sent; SignalServiceDataMessage dataMessage = CreateSignalServiceMessage(metadata, sentContent.Message); SignalServiceAddress? address = SignalServiceAddress.IsValidAddress(sentContent.DestinationUuid, sentContent.Destination) ? new SignalServiceAddress(UuidUtil.ParseOrNull(sentContent.DestinationUuid), sentContent.Destination) : null; if (address == null && dataMessage.Group == null) { throw new ProtocolInvalidMessageException(new InvalidMessageException("SyncMessage missing both destination and group ID!"), null, 0); } foreach (var status in sentContent.UnidentifiedStatus) { if (SignalServiceAddress.IsValidAddress(status.DestinationUuid, status.Destination)) { SignalServiceAddress recipient = new SignalServiceAddress(UuidUtil.ParseOrNull(status.DestinationUuid), status.Destination); unidentifiedStatuses.Add(recipient, status.Unidentified); } else { logger.LogWarning("Encountered an invalid UnidentifiedDeliveryStatus in a SentTranscript! Ignoring."); } } return(SignalServiceSyncMessage.ForSentTranscript(new SentTranscriptMessage(address !, (long)sentContent.Timestamp, CreateSignalServiceMessage(metadata, sentContent.Message), (long)sentContent.ExpirationStartTimestamp, unidentifiedStatuses, sentContent.IsRecipientUpdate))); } if (content.Request != null) { return(SignalServiceSyncMessage.ForRequest(new RequestMessage(content.Request))); } if (content.Read.Count > 0) { List <ReadMessage> readMessages = new List <ReadMessage>(); foreach (SyncMessage.Types.Read read in content.Read) { if (SignalServiceAddress.IsValidAddress(read.SenderUuid, read.Sender)) { SignalServiceAddress address = new SignalServiceAddress(UuidUtil.ParseOrNull(read.SenderUuid), read.Sender); readMessages.Add(new ReadMessage(address, (long)read.Timestamp)); } else { logger.LogWarning("Encountered an invalid ReadMessage! Ignoring."); } } return(SignalServiceSyncMessage.ForRead(readMessages)); } if (content.ViewOnceOpen != null) { if (SignalServiceAddress.IsValidAddress(content.ViewOnceOpen.SenderUuid, content.ViewOnceOpen.Sender)) { SignalServiceAddress address = new SignalServiceAddress(UuidUtil.ParseOrNull(content.ViewOnceOpen.SenderUuid), content.ViewOnceOpen.Sender); ViewOnceOpenMessage timerRead = new ViewOnceOpenMessage(address, (long)content.ViewOnceOpen.Timestamp); return(SignalServiceSyncMessage.ForViewOnceOpen(timerRead)); } else { throw new ProtocolInvalidMessageException(new InvalidMessageException("ViewOnceOpen message has no sender!"), null, 0); } } if (content.Contacts != null) { AttachmentPointer pointer = content.Contacts.Blob; return(SignalServiceSyncMessage.ForContacts(new ContactsMessage(CreateAttachmentPointer(pointer), content.Contacts.Complete))); } if (content.Groups != null) { AttachmentPointer pointer = content.Groups.Blob; return(SignalServiceSyncMessage.ForGroups(CreateAttachmentPointer(pointer))); } if (content.Verified != null) { if (SignalServiceAddress.IsValidAddress(content.Verified.DestinationUuid, content.Verified.Destination)) { try { Verified verified = content.Verified; SignalServiceAddress destination = new SignalServiceAddress(UuidUtil.ParseOrNull(verified.DestinationUuid), verified.Destination); IdentityKey identityKey = new IdentityKey(verified.IdentityKey.ToByteArray(), 0); VerifiedMessage.VerifiedState verifiedState; if (verified.State == Verified.Types.State.Default) { verifiedState = VerifiedMessage.VerifiedState.Default; } else if (verified.State == Verified.Types.State.Verified) { verifiedState = VerifiedMessage.VerifiedState.Verified; } else if (verified.State == Verified.Types.State.Unverified) { verifiedState = VerifiedMessage.VerifiedState.Unverified; } else { throw new ProtocolInvalidMessageException(new InvalidMessageException($"Unknown state: {(int)verified.State}"), metadata.Sender.GetIdentifier(), metadata.SenderDevice); } return(SignalServiceSyncMessage.ForVerified(new VerifiedMessage(destination, identityKey, verifiedState, Util.CurrentTimeMillis()))); } catch (InvalidKeyException ex) { throw new ProtocolInvalidKeyException(ex, metadata.Sender.GetIdentifier(), metadata.SenderDevice); } } else { throw new ProtocolInvalidMessageException(new InvalidMessageException("Verified message has no sender!"), null, 0); } } if (content.StickerPackOperation.Count > 0) { List <StickerPackOperationMessage> operations = new List <StickerPackOperationMessage>(); foreach (var operation in content.StickerPackOperation) { byte[]? packId = operation.HasPackId ? operation.PackId.ToByteArray() : null; byte[]? packKey = operation.HasPackKey ? operation.PackKey.ToByteArray() : null; StickerPackOperationMessage.OperationType?type = null; if (operation.HasType) { switch (operation.Type) { case SyncMessage.Types.StickerPackOperation.Types.Type.Install: type = StickerPackOperationMessage.OperationType.Install; break; case SyncMessage.Types.StickerPackOperation.Types.Type.Remove: type = StickerPackOperationMessage.OperationType.Remove; break; } } operations.Add(new StickerPackOperationMessage(packId, packKey, type)); } return(SignalServiceSyncMessage.ForStickerPackOperations(operations)); } if (content.Blocked != null) { List <string> numbers = content.Blocked.Numbers.ToList(); List <string> uuids = content.Blocked.Uuids.ToList(); List <SignalServiceAddress> addresses = new List <SignalServiceAddress>(numbers.Count + uuids.Count); List <byte[]> groupIds = new List <byte[]>(content.Blocked.GroupIds.Count); foreach (string e164 in numbers) { SignalServiceAddress?address = SignalServiceAddress.FromRaw(null, e164); if (address != null) { addresses.Add(address); } } foreach (string uuid in uuids) { SignalServiceAddress?address = SignalServiceAddress.FromRaw(uuid, null); if (address != null) { addresses.Add(address); } } foreach (ByteString groupId in content.Blocked.GroupIds) { groupIds.Add(groupId.ToByteArray()); } return(SignalServiceSyncMessage.ForBlocked(new BlockedListMessage(addresses, groupIds))); } if (content.Configuration != null) { bool?readReceipts = content.Configuration.HasReadReceipts ? content.Configuration.ReadReceipts : (bool?)null; bool?unidentifiedDeliveryIndicators = content.Configuration.HasUnidentifiedDeliveryIndicators ? content.Configuration.UnidentifiedDeliveryIndicators : (bool?)null; bool?typingIndicators = content.Configuration.HasTypingIndicators ? content.Configuration.TypingIndicators : (bool?)null; bool?linkPreviews = content.Configuration.HasLinkPreviews ? content.Configuration.LinkPreviews : (bool?)null; return(SignalServiceSyncMessage.ForConfiguration(new ConfigurationMessage(readReceipts, unidentifiedDeliveryIndicators, typingIndicators, linkPreviews))); } return(SignalServiceSyncMessage.Empty()); }
/// <summary> /// Takes internal protobuf serialization format and processes it into a <see cref="SignalServiceContent"/>. /// </summary> /// <param name="serviceContentProto"></param> /// <returns></returns> /// <exception cref="ProtocolInvalidMessageException"></exception> /// <exception cref="ProtocolInvalidKeyException"></exception> public static SignalServiceContent?CreateFromProto(SignalServiceContentProto serviceContentProto) { SignalServiceMetadata metadata = SignalServiceMetadataProtobufSerializer.FromProtobuf(serviceContentProto.Metadata); SignalServiceAddress localAddress = SignalServiceAddressProtobufSerializer.FromProtobuf(serviceContentProto.LocalAddress); if (serviceContentProto.DataCase == SignalServiceContentProto.DataOneofCase.LegacyDataMessage) { DataMessage message = serviceContentProto.LegacyDataMessage; return(new SignalServiceContent(CreateSignalServiceMessage(metadata, message), metadata.Sender, metadata.SenderDevice, metadata.Timestamp, metadata.NeedsReceipt, serviceContentProto)); } else if (serviceContentProto.DataCase == SignalServiceContentProto.DataOneofCase.Content) { Content message = serviceContentProto.Content; if (message.DataMessage != null) { return(new SignalServiceContent(CreateSignalServiceMessage(metadata, message.DataMessage), metadata.Sender, metadata.SenderDevice, metadata.Timestamp, metadata.NeedsReceipt, serviceContentProto)); } else if (message.SyncMessage != null && localAddress.Matches(metadata.Sender)) { return(new SignalServiceContent(CreateSynchronizeMessage(metadata, message.SyncMessage), metadata.Sender, metadata.SenderDevice, metadata.Timestamp, metadata.NeedsReceipt, serviceContentProto)); } else if (message.CallingMessage != null) { return(new SignalServiceContent(CreateCallingMessage(message.CallingMessage), metadata.Sender, metadata.SenderDevice, metadata.Timestamp, metadata.NeedsReceipt, serviceContentProto)); } else if (message.ReceiptMessage != null) { return(new SignalServiceContent(CreateReceiptMessage(metadata, message.ReceiptMessage), metadata.Sender, metadata.SenderDevice, metadata.Timestamp, metadata.NeedsReceipt, serviceContentProto)); } else if (message.TypingMessage != null) { return(new SignalServiceContent(CreateTypingMessage(metadata, message.TypingMessage), metadata.Sender, metadata.SenderDevice, metadata.Timestamp, false, serviceContentProto)); } } return(null); }