private async Task TryScheduleAttachmentDownload(SignalAttachment attachment)
        {
            if (Downloads.Count < 100)
            {
                if (attachment.Status != SignalAttachmentStatus.Finished && !Downloads.ContainsKey(attachment.Id))
                {
                    SignalServiceAttachmentPointer attachmentPointer = attachment.ToAttachmentPointer();
                    IStorageFolder localFolder = ApplicationData.Current.LocalFolder;
                    IStorageFile   tmpDownload = await Task.Run(async() =>
                    {
                        return(await ApplicationData.Current.LocalCacheFolder.CreateFileAsync(@"Attachments\" + attachment.Id + ".cipher", CreationCollisionOption.ReplaceExisting));
                    });

                    BackgroundDownloader downloader = new BackgroundDownloader();
                    downloader.SetRequestHeader("Content-Type", "application/octet-stream");
                    // this is the recommended way to call CreateDownload
                    // see https://docs.microsoft.com/en-us/uwp/api/windows.networking.backgroundtransfer.backgrounddownloader#Methods
                    DownloadOperation download = downloader.CreateDownload(new Uri(await MessageReceiver.RetrieveAttachmentDownloadUrl(CancelSource.Token, attachmentPointer)), tmpDownload);
                    attachment.Guid = download.Guid.ToString();
                    SignalDBContext.UpdateAttachmentGuid(attachment);
                    Downloads.Add(attachment.Id, download);
                    var downloadSuccessfulHandler = Task.Run(async() =>
                    {
                        Logger.LogInformation("Waiting for download {0}({1})", attachment.SentFileName, attachment.Id);
                        var t = await download.StartAsync();
                        await HandleSuccessfullDownload(attachment, tmpDownload, download);
                    });
                }
            }
        }
        /// <summary>
        /// Retrieves a SignalServiceAttachment
        /// </summary>
        /// <param name="token"></param>
        /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/>
        /// received in a <see cref="SignalServiceDataMessage"/></param>
        /// <param name="tmpCipherDestination">The temporary destination for this attachment before decryption</param>
        /// <param name="maxSizeBytes">The maximum size for this attachment (not yet implemented)</param>
        /// <param name="listener">An optional listener (may be null) to receive callbacks on download progress.</param>
        public async Task <Stream> RetrieveAttachment(CancellationToken token, SignalServiceAttachmentPointer pointer, Stream tmpCipherDestination, int maxSizeBytes, IProgressListener listener)
        {
            await Socket.RetrieveAttachment(token, pointer.Id, tmpCipherDestination, maxSizeBytes);

            tmpCipherDestination.Position = 0;
            return(AttachmentCipherInputStream.CreateFor(tmpCipherDestination, pointer.Size != null ? pointer.Size.Value : 0, pointer.Key, pointer.Digest));
        }
        /// <summary>
        /// Retrieves a SignalServiceAttachment
        /// </summary>
        /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/>
        /// received in a <see cref="SignalServiceDataMessage"/></param>
        /// <param name="plaintextDestination">The download destination for this attachment.</param>
        /// <param name="tmpCipherDestination">The temporary destination for this attachment before decryption</param>
        /// <param name="maxSizeBytes">The maximum size for this attachment (not yet implemented)</param>
        /// <param name="listener">An optional listener (may be null) to receive callbacks on download progress.</param>
        public void retrieveAttachment(SignalServiceAttachmentPointer pointer, FileStream plaintextDestination, FileStream tmpCipherDestination, int maxSizeBytes, ProgressListener listener)
        {
            socket.retrieveAttachment(pointer.Relay, pointer.Id, tmpCipherDestination, maxSizeBytes);
            tmpCipherDestination.Seek(0, SeekOrigin.Begin);

            byte[] combinedKeyMaterial = pointer.Key;
            byte[][] parts = Util.split(combinedKeyMaterial, CIPHER_KEY_SIZE, MAC_KEY_SIZE);
            //byte[] digest = pointer.getDigest(); //TODO
            //verifyMac()

            byte[] iv = new byte[BLOCK_SIZE];
            Util.readFully(tmpCipherDestination, iv);

            using (var aes = Aes.Create())
            {
                aes.Key = parts[0];
                aes.IV = iv;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                using (var decrypt = aes.CreateDecryptor())
                using (var cryptoStream = new CryptoStream(tmpCipherDestination, decrypt, CryptoStreamMode.Read))
                {
                    byte[] buffer = new byte[CIPHER_KEY_SIZE];
                    int read = cryptoStream.Read(buffer, 0, buffer.Length);
                    while (read > 0)
                    {
                        plaintextDestination.Write(buffer, 0, read);
                        read = cryptoStream.Read(buffer, 0, buffer.Length);
                    }
                }
            }
        }
        private void DecryptAttachment(SignalServiceAttachmentPointer pointer, Stream ciphertextFileStream, Stream plaintextFileStream)
        {
            byte[] buf = new byte[32];
            Stream s   = AttachmentCipherInputStream.CreateFor(ciphertextFileStream, pointer.Size != null ? pointer.Size.Value : 0, pointer.Key, pointer.Digest);

            s.CopyTo(plaintextFileStream);
        }
        /// <summary>
        /// Retrieves a SignalServiceAttachment.
        /// </summary>
        /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/> received in a <see cref="SignalServiceDataMessage"/>.</param>
        /// <param name="destination">The download destination for this attachment.</param>
        /// <param name="maxSizeBytes"></param>
        /// <param name="token"></param>
        /// <returns>A Stream that streams the plaintext attachment contents.</returns>
        /// <exception cref="IOException"></exception>
        /// <exception cref="InvalidMessageException"></exception>
        public async Task <Stream> RetrieveAttachmentAsync(SignalServiceAttachmentPointer pointer, Stream destination, int maxSizeBytes, CancellationToken?token = null)
        {
            if (token == null)
            {
                token = CancellationToken.None;
            }

            return(await RetrieveAttachmentAsync(pointer, destination, maxSizeBytes, null, token));
        }
Exemple #6
0
        private SignalServiceGroup createGroupInfo(SignalServiceEnvelope envelope, DataMessage content)
        {
            if (!content.HasGroup)
            {
                return(null);
            }

            SignalServiceGroup.Type type;

            switch (content.Group.Type)
            {
            case GroupContext.Types.Type.DELIVER: type = SignalServiceGroup.Type.DELIVER; break;

            case GroupContext.Types.Type.UPDATE: type = SignalServiceGroup.Type.UPDATE; break;

            case GroupContext.Types.Type.QUIT: type = SignalServiceGroup.Type.QUIT; break;

            case GroupContext.Types.Type.REQUEST_INFO: type = SignalServiceGroup.Type.REQUEST_INFO; break;

            default: type = SignalServiceGroup.Type.UNKNOWN; break;
            }

            if (content.Group.Type != GroupContext.Types.Type.DELIVER)
            {
                String         name    = null;
                IList <String> members = null;
                SignalServiceAttachmentPointer avatar = null;

                if (content.Group.HasName)
                {
                    name = content.Group.Name;
                }

                if (content.Group.MembersCount > 0)
                {
                    members = content.Group.MembersList;
                }

                if (content.Group.HasAvatar)
                {
                    avatar = new SignalServiceAttachmentPointer(content.Group.Avatar.Id,
                                                                content.Group.Avatar.ContentType,
                                                                content.Group.Avatar.Key.ToByteArray(),
                                                                envelope.getRelay());
                }

                return(new SignalServiceGroup(type, content.Group.Id.ToByteArray(), name, members, avatar));
            }

            return(new SignalServiceGroup(content.Group.Id.ToByteArray()));
        }
        /// <summary>
        /// Retrieves a SignalServiceAttachment
        /// </summary>
        /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/>
        /// received in a <see cref="SignalServiceDataMessage"/></param>
        /// <param name="destination">The download destination for this attachment.</param>
        /// <param name="maxSizeBytes"></param>
        /// <param name="listener">An optional listener (may be null) to receive callbacks on download progress.</param>
        /// <param name="token"></param>
        /// <exception cref="IOException"></exception>
        /// <exception cref="InvalidMessageException"></exception>
        public async Task <Stream> RetrieveAttachmentAsync(SignalServiceAttachmentPointer pointer, Stream destination, int maxSizeBytes, IProgressListener?listener, CancellationToken?token = null)
        {
            if (token == null)
            {
                token = CancellationToken.None;
            }

            if (pointer.Digest == null)
            {
                throw new InvalidMessageException("No attachment digest!");
            }

            await socket.RetrieveAttachmentAsync(pointer.CdnNumber, pointer.RemoteId, destination, maxSizeBytes, listener, token);

            destination.Position = 0;
            return(AttachmentCipherInputStream.CreateForAttachment(destination, pointer.Size != null ? pointer.Size.Value : 0, pointer.Key, pointer.Digest));
        }
Exemple #8
0
        private AttachmentPointer CreateAttachmentPointerFromPointer(SignalServiceAttachmentPointer attachment)
        {
            var attachmentPointer = new AttachmentPointer()
            {
                ContentType = attachment.ContentType,
                Id          = attachment.Id,
                Key         = ByteString.CopyFrom(attachment.Key),
                Digest      = ByteString.CopyFrom(attachment.Digest),
                Size        = (uint)attachment.Size
            };

            if (attachment.FileName != null)
            {
                attachmentPointer.FileName = attachment.FileName;
            }

            if (attachment.VoiceNote)
            {
                attachmentPointer.Flags = (uint)AttachmentPointer.Types.Flags.VoiceMessage;
            }

            return(attachmentPointer);
        }
 /// <summary>
 /// Retrieves an attachment URL location
 /// </summary>
 /// <param name="token"></param>
 /// <param name="pointer">The pointer to the attachment</param>
 /// <returns></returns>
 public async Task <string> RetrieveAttachmentDownloadUrl(CancellationToken token, SignalServiceAttachmentPointer pointer)
 {
     return(await Socket.RetrieveAttachmentDownloadUrl(token, pointer.Id));
 }
        private SignalServiceGroup createGroupInfo(SignalServiceEnvelope envelope, DataMessage content)
        {
            if (content.GroupOneofCase == DataMessage.GroupOneofOneofCase.None)
            {
                return(null);
            }

            SignalServiceGroup.GroupType type;

            switch (content.Group.Type)
            {
            case GroupContext.Types.Type.Deliver: type = SignalServiceGroup.GroupType.DELIVER; break;

            case GroupContext.Types.Type.Update: type = SignalServiceGroup.GroupType.UPDATE; break;

            case GroupContext.Types.Type.Quit: type = SignalServiceGroup.GroupType.QUIT; break;

            case GroupContext.Types.Type.RequestInfo: type = SignalServiceGroup.GroupType.REQUEST_INFO; break;

            default: type = SignalServiceGroup.GroupType.UNKNOWN; break;
            }

            if (content.Group.Type != GroupContext.Types.Type.Deliver)
            {
                String         name    = null;
                IList <String> members = null;
                SignalServiceAttachmentPointer avatar = null;

                if (content.Group.NameOneofCase == GroupContext.NameOneofOneofCase.Name)
                {
                    name = content.Group.Name;
                }

                if (content.Group.Members.Count > 0)
                {
                    members = content.Group.Members;
                }

                if (content.Group.AvatarOneofCase == GroupContext.AvatarOneofOneofCase.Avatar)
                {
                    AttachmentPointer pointer = content.Group.Avatar;

                    avatar = new SignalServiceAttachmentPointer(pointer.Id,
                                                                pointer.ContentType,
                                                                pointer.Key.ToByteArray(),
                                                                envelope.getRelay(),
                                                                pointer.Digest.ToByteArray(),
                                                                null,
                                                                false);
                }

                return(new SignalServiceGroup()
                {
                    Type = type,
                    GroupId = content.Group.Id.ToByteArray(),
                    Name = name,
                    Members = members,
                    Avatar = avatar
                });
            }

            return(new SignalServiceGroup()
            {
                GroupId = content.Group.Id.ToByteArray(),
                Type = type
            });
        }
 public string RetrieveAttachmentDownloadUrl(SignalServiceAttachmentPointer pointer)
 {
     return(socket.RetrieveAttachmentDownloadUrl(pointer.CdnNumber, pointer.RemoteId));
 }
 /// <summary>
 /// Retrieves a SignalServiceAttachment
 /// </summary>
 /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/>
 /// received in a <see cref="SignalServiceDataMessage"/></param>
 /// <param name="destination">The download destination for this attachment.</param>
 /// <param name="listener">An optional listener (may be null) to receive callbacks on download progress.</param>
 /// <returns>A Stream that streams the plaintext attachment contents.</returns>
 public Stream retrieveAttachment(SignalServiceAttachmentPointer pointer, StorageFile destination, ProgressListener listener)
 {
     throw new NotImplementedException();
     return(new MemoryStream());
 }
 /// <summary>
 /// Retrieves a SignalServiceAttachment
 /// </summary>
 /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/>
 /// received in a <see cref="SignalServiceDataMessage"/></param>
 /// <param name="destination">The download destination for this attachment.</param>
 /// <returns>A Stream that streams the plaintext attachment contents.</returns>
 public Stream retrieveAttachment(SignalServiceAttachmentPointer pointer, StorageFile destination)
 {
     throw new NotImplementedException();
     return(retrieveAttachment(pointer, destination, null));
 }
Exemple #14
0
        private SignalServiceGroup?CreateGroupInfo(DataMessage content)
        {
            if (content.GroupOneofCase == DataMessage.GroupOneofOneofCase.None)
            {
                return(null);
            }

            var type = content.Group.Type switch
            {
                GroupContext.Types.Type.Deliver => SignalServiceGroup.GroupType.DELIVER,
                GroupContext.Types.Type.Update => SignalServiceGroup.GroupType.UPDATE,
                GroupContext.Types.Type.Quit => SignalServiceGroup.GroupType.QUIT,
                GroupContext.Types.Type.RequestInfo => SignalServiceGroup.GroupType.REQUEST_INFO,
                _ => SignalServiceGroup.GroupType.UNKNOWN,
            };

            if (content.Group.Type != GroupContext.Types.Type.Deliver)
            {
                string?        name    = null;
                IList <string>?members = null;
                SignalServiceAttachmentPointer?avatar = null;

                if (content.Group.NameOneofCase == GroupContext.NameOneofOneofCase.Name)
                {
                    name = content.Group.Name;
                }

                if (content.Group.Members.Count > 0)
                {
                    members = content.Group.Members;
                }

                if (content.Group.AvatarOneofCase == GroupContext.AvatarOneofOneofCase.Avatar)
                {
                    AttachmentPointer pointer = content.Group.Avatar;

                    avatar = new SignalServiceAttachmentPointer(pointer.Id,
                                                                pointer.ContentType,
                                                                pointer.Key.ToByteArray(),
                                                                pointer.SizeOneofCase == AttachmentPointer.SizeOneofOneofCase.Size ? pointer.Size : 0,
                                                                null,
                                                                0, 0,
                                                                pointer.DigestOneofCase == AttachmentPointer.DigestOneofOneofCase.Digest ? pointer.Digest.ToByteArray() : null,
                                                                null,
                                                                false);
                }

                return(new SignalServiceGroup()
                {
                    Type = type,
                    GroupId = content.Group.Id.ToByteArray(),
                    Name = name,
                    Members = members,
                    Avatar = avatar
                });
            }

            return(new SignalServiceGroup()
            {
                GroupId = content.Group.Id.ToByteArray(),
                Type = type
            });
        }
 /// <summary>
 /// Retrieves a SignalServiceAttachment
 /// </summary>
 /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/>
 /// received in a <see cref="SignalServiceDataMessage"/></param>
 /// <param name="plaintextDestination">The download destination for this attachment.</param>
 /// <param name="tmpCipherDestination">The temporary destination for this attachment before decryption</param>
 public void retrieveAttachment(SignalServiceAttachmentPointer pointer, FileStream plaintextDestination, FileStream tmpCipherDestination, int maxSizeBytes)
 {
     retrieveAttachment(pointer, plaintextDestination, tmpCipherDestination, maxSizeBytes, null);
 }