예제 #1
0
        private async Task SendMessageResponseAsync(DataSourceRequest request)
        {
            var id        = long.Parse(request.Path.Split('/')[1]);
            var arguments = request.Url.PathAndQuery.ToPageArguments();

            var mime = await LoadMessageBytesAsync(id);

            var reader = new MailMessageReader(mime);
            var view   = FindPreferredView(reader);

            if (string.IsNullOrWhiteSpace(view))
            {
                SendResponse(request, DataSourceResponse.Empty);
                return;
            }

            const string key            = "blockExternals";
            var          blockExternals = !arguments.ContainsKey(key) || bool.Parse(arguments[key]);

            view = NormalizeHtml(view);
            view = ConvertEmbeddedSources(view, id);
            view = RemoveJavaScript(view);
            view = InjectParanoiaScripts(view);

            if (blockExternals)
            {
                view = RemoveExternalSources(view);
            }

            var bytes = Encoding.UTF8.GetBytes(view);

            SendHtmlResponse(request, bytes);
        }
        private async void PrepareAsReply(IReadOnlyDictionary <string, string> arguments)
        {
            MailContactContext from;
            MailMessageReader  message;
            var id = Int64.Parse(arguments["id"]);

            using (var database = new DatabaseContext()) {
                var mime = await database.MimeMessages
                           .Where(x => x.MessageId == id)
                           .ToArrayAsync();

                if (!mime.Any())
                {
                    throw new InvalidOperationException(Properties.Resources.MessageNotFoundException);
                }

                message = new MailMessageReader(mime[0].Data);
                from    = new MailContactContext(await database.MailContacts
                                                 .FirstAsync(x => x.Address == message.Headers.From.Address));
            }

            var context = (MailCompositionContext)DataContext;

            context.Subject = string.Format("{0} {1}", Settings.Default.PrefixForAnswering, message.Headers.Subject);
            context.Source  = string.Format("asset://paranoia/message/reply?id={0}", id);

            await from.CheckSecurityStateAsync();

            RecipientsBox.Preset(new[] { from });
        }
예제 #3
0
        private async Task SendQuotedResponseAsync(DataSourceRequest request)
        {
            var variables = new Dictionary <string, string> {
                { "header", string.Empty },
                { "default_font_size", string.Format("{0}", Settings.Default.HtmlDefaultFontSize) },
                { "default_font_family", string.Format("{0}", Settings.Default.HtmlDefaultFontFamily) }
            };

            long messageId;
            var  arguments = request.Url.OriginalString.ToPageArguments();

            if (arguments.ContainsKey("id") && long.TryParse(arguments["id"], out messageId))
            {
                var bytes = await LoadMessageBytesAsync(messageId);

                var reader = new MailMessageReader(bytes);
                var view   = FindPreferredView(reader);

                view = ConvertEmbeddedSources(view, messageId);
                view = string.Format("<hr style=\"margin:20px 0px;\"/>{0}", view);
                variables.Add("quote", view);
            }

            if (!variables.Keys.Contains("quote"))
            {
                variables.Add("quote", string.Empty);
            }

            var html = GenerateEditorHtml(variables);

            SendHtmlResponse(request, Encoding.UTF8.GetBytes(html));
        }
예제 #4
0
        internal async Task UpdateTrustLevelAsync()
        {
            using (var database = new DatabaseContext()) {
                var mime = await database.MimeMessages.FirstAsync(x => x.MessageId == Id);

                var reader = new MailMessageReader(mime.Data);

                var part = reader.FindFirstHtmlVersion();
                if (part == null)
                {
                    return;
                }

                var          text    = part.GetBodyAsText();
                const string pattern = "(href|src)\\s*=\\s*(\"|&quot;).+?(\"|&quot;)";
                HasExternals = Regex.IsMatch(text, pattern,
                                             RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);

                if (!HasExternals)
                {
                    return;
                }

                var contact = await database.MailContacts
                              .FirstOrDefaultAsync(x => x.Address == FromAddress);

                IsSourceTrusted = contact != null && contact.IsTrusted;
            }
        }
        private async void PrepareAsReplyAll(IReadOnlyDictionary <string, string> arguments)
        {
            MailContactContext from;
            var carbonCopies      = new List <MailContactContext>();
            var blindCarbonCopies = new List <MailContactContext>();
            MailMessageReader message;
            var id = Int64.Parse(arguments["id"]);

            using (var database = new DatabaseContext()) {
                var mime = await database.MimeMessages
                           .Where(x => x.MessageId == id)
                           .ToArrayAsync();

                if (!mime.Any())
                {
                    throw new InvalidOperationException(Properties.Resources.MessageNotFoundException);
                }

                message = new MailMessageReader(mime[0].Data);
                from    = new MailContactContext(await database.MailContacts
                                                 .FirstAsync(x => x.Address == message.Headers.From.Address));

                foreach (var cc in message.Headers.Cc.Where(y =>
                                                            !App.Context.Accounts.Any(x => x.Address.EqualsIgnoreCase(y.Address))))
                {
                    var lcc     = cc;
                    var contact = new MailContactContext(await database.MailContacts
                                                         .FirstAsync(x => x.Address == lcc.Address));

                    await contact.CheckSecurityStateAsync();

                    carbonCopies.Add(contact);
                }

                foreach (var bcc in message.Headers.Bcc.Where(y =>
                                                              !App.Context.Accounts.Any(x => x.Address.EqualsIgnoreCase(y.Address))))
                {
                    var lbcc    = bcc;
                    var contact = new MailContactContext(await database.MailContacts
                                                         .FirstAsync(x => x.Address == lbcc.Address));

                    await contact.CheckSecurityStateAsync();

                    blindCarbonCopies.Add(contact);
                }
            }

            var context = (MailCompositionContext)DataContext;

            context.Subject = string.Format("{0} {1}", Settings.Default.PrefixForAnswering, message.Headers.Subject);
            context.Source  = string.Format("asset://paranoia/message/reply?id={0}", id);

            await from.CheckSecurityStateAsync();

            RecipientsBox.Preset(new[] { from });

            CarbonCopyBox.Preset(carbonCopies);
            BlindCarbonCopyBox.Preset(blindCarbonCopies);
        }
예제 #6
0
        private static async Task ProcessChallengeAsync(ImapEnvelope envelope, ImapMailbox mailbox)
        {
            var bytes = await mailbox.FetchMessageBodyAsync(envelope.Uid);

            var message = new MailMessageReader(bytes);

            var token     = string.Empty;
            var nonce     = string.Empty;
            var publicKey = string.Empty;

            const string pattern = @"\s|\t|\n|\r";

            var xHeaders = message.Headers.UnknownHeaders;

            for (var i = 0; i < xHeaders.Keys.Count; i++)
            {
                var key = xHeaders.Keys[i];

                var values = xHeaders.GetValues(i);
                if (values == null)
                {
                    throw new NullReferenceException(Resources.ChallengeCorruptException);
                }

                if (string.Compare(key, ParanoiaHeaderKeys.Token, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    token = values.FirstOrDefault() ?? string.Empty;
                    token = Regex.Replace(token, pattern, string.Empty);
                    continue;
                }

                if (string.Compare(key, ParanoiaHeaderKeys.Nonce, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    nonce = values.FirstOrDefault() ?? string.Empty;
                    nonce = Regex.Replace(nonce, pattern, string.Empty);
                    continue;
                }

                if (string.Compare(key, ParanoiaHeaderKeys.PublicKey, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    publicKey = values.FirstOrDefault() ?? string.Empty;
                    publicKey = Regex.Replace(publicKey, pattern, string.Empty);
                }
            }

            if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(nonce) || string.IsNullOrEmpty(publicKey))
            {
                throw new InvalidDataException(Resources.ChallengeCorruptException);
            }


            var data = App.Context.KeyContainer.DecryptWithPrivateKey(
                Convert.FromBase64String(token),
                Convert.FromBase64String(publicKey),
                Convert.FromBase64String(nonce));

            await RespondToChallengeAsync(Encoding.UTF8.GetString(data));
        }
        /// <summary>
        ///     Finds the first <see cref="MessagePart" /> with the given MediaType
        /// </summary>
        /// <param name="message"> The <see cref="MailMessageReader" /> to start looking in </param>
        /// <param name="question"> The MediaType to look for. Case is ignored. </param>
        /// <returns>
        ///     A <see cref="MessagePart" /> with the given MediaType or <see langword="null" /> if no such
        ///     <see
        ///         cref="MessagePart" />
        ///     was found
        /// </returns>
        public MessagePart VisitMessage(MailMessageReader message, string question)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            return(VisitMessagePart(message.MessagePart, question));
        }
예제 #8
0
        /// <summary>
        ///     Call this when you want an answer for a full message.
        /// </summary>
        /// <param name="message"> The message you want to traverse </param>
        /// <returns> An answer </returns>
        /// <exception cref="ArgumentNullException">
        ///     if
        ///     <paramref name="message" />
        ///     is
        ///     <see langword="null" />
        /// </exception>
        public TAnswer VisitMessage(MailMessageReader message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            return(VisitMessagePart(message.MessagePart));
        }
예제 #9
0
        private static async Task <DecryptionResult> DecryptPart(MailMessageReader reader, MessagePart part)
        {
            try {
                var address   = reader.Headers.From.Address;
                var publicKey = reader.Headers.UnknownHeaders.Get(ParanoiaHeaderKeys.PublicKey);

                byte[] messageBytes, nonceBytes;
                using (var r = new BinaryReader(new MemoryStream(part.Body))) {
                    nonceBytes   = r.ReadBytes(PublicKeyCrypto.NonceSize);
                    messageBytes = r.ReadBytes(part.Body.Length - nonceBytes.Length);
                }

                using (var database = new DatabaseContext()) {
                    var contact = await database.MailContacts.FirstOrDefaultAsync(x => x.Address == address);

                    if (contact == null)
                    {
                        throw new Exception("Contact not found exception.");
                    }

                    var keys = await database.PublicKeys.Where(x => x.ContactId == contact.Id).ToArrayAsync();

                    if (keys.All(x => string.Compare(publicKey, x.Data, StringComparison.InvariantCulture) != 0))
                    {
                        var ownKey = Convert.ToBase64String(App.Context.KeyContainer.PublicKey);
                        if (string.Compare(ownKey, publicKey, StringComparison.Ordinal) != 0)
                        {
                            return(new DecryptionResult {
                                IsSuccessful = false
                            });
                        }
                    }
                }

                var keyBytes = Convert.FromBase64String(publicKey);
                return(new DecryptionResult {
                    IsSuccessful = true,
                    Bytes = App.Context.KeyContainer.DecryptWithPrivateKey(messageBytes, keyBytes, nonceBytes)
                });
            } catch (Exception ex) {
                Logger.Error(ex);
                return(new DecryptionResult {
                    IsSuccessful = false
                });
            }
        }
예제 #10
0
        private static string FindPreferredView(MailMessageReader reader)
        {
            string text;
            var    html = reader.FindFirstHtmlVersion();

            if (html == null)
            {
                var plain = reader.FindFirstPlainTextVersion();
                text = plain != null
                    ? FormatPlainText(reader.Headers.Subject, plain.GetBodyAsText())
                    : string.Empty;
            }
            else
            {
                text = html.GetBodyAsText();
            }

            return(text);
        }
예제 #11
0
        internal static byte[] GetAttachmentBytes(string cid, long messageId)
        {
            using (var database = new DatabaseContext()) {
                var message = database.MimeMessages.FirstOrDefault(x => x.MessageId == messageId);

                if (message != null)
                {
                    var reader      = new MailMessageReader(message.Data);
                    var attachments = reader.FindAllAttachments();
                    var attachment  = attachments.FirstOrDefault(x => x.ContentId == Uri.UnescapeDataString(cid));
                    if (attachment != null)
                    {
                        return(attachment.Body);
                    }
                }
            }

            return(null);
        }
예제 #12
0
        private static async Task <byte[]> FindRelevantPartAsync(byte[] mime)
        {
            var reader         = new MailMessageReader(mime);
            var encryptedParts = reader.FindAllMessagePartsWithMediaType(MediaTypes.EncryptedMime);

            if (encryptedParts == null || encryptedParts.Count == 0)
            {
                return(mime);
            }

            foreach (var part in encryptedParts)
            {
                var result = await DecryptPart(reader, part);

                if (result.IsSuccessful)
                {
                    return(result.Bytes);
                }
            }

            throw new MessageDecryptionFailedException();
        }
예제 #13
0
        private async Task DisplayAttachmentAsync(MailMessageContext message)
        {
            var attachmentContexts = new List <AttachmentContext>();

            using (var context = new DatabaseContext()) {
                var mimeMessage = await context.MimeMessages.FirstOrDefaultAsync(x => x.MessageId == message.Id);

                if (mimeMessage == null)
                {
                    return;
                }

                var reader      = new MailMessageReader(mimeMessage.Data);
                var attachments = reader.FindAllAttachments();

                attachments.Where(x => x.ContentId == null)
                .ForEach(y => attachmentContexts.Add(new AttachmentContext(y)));
            }
            Application.Current.Dispatcher.Invoke(() => {
                Attachments.Clear();
                Attachments.AddRange(attachmentContexts);
            });
        }
        private async void PrepareAsForward(IReadOnlyDictionary <string, string> arguments)
        {
            MailMessageReader message;
            var id = Int64.Parse(arguments["id"]);

            using (var database = new DatabaseContext()) {
                var mime = await database.MimeMessages
                           .Where(x => x.MessageId == id)
                           .ToArrayAsync();

                if (!mime.Any())
                {
                    throw new InvalidOperationException(Properties.Resources.MessageNotFoundException);
                }

                message = new MailMessageReader(mime[0].Data);
            }

            var context = (MailCompositionContext)DataContext;

            context.Subject = string.Format("{0} {1}", Settings.Default.PrefixForForwarding, message.Headers.Subject);
            context.Source  = string.Format("asset://paranoia/message/forward?id={0}", id);
        }
예제 #15
0
        private async Task SendFileResponseAsync(DataSourceRequest request)
        {
            const string key       = "path";
            var          arguments = request.Path.ToPageArguments();

            if (!arguments.ContainsKey(key))
            {
                throw new KeyNotFoundException(key);
            }

            var path     = arguments[key];
            var filename = Uri.UnescapeDataString(path);

            var bytes = await LoadMessageBytesAsync(new FileInfo(filename));

            var reader = new MailMessageReader(bytes);
            var view   = FindPreferredView(reader);

            view = NormalizeHtml(view);
            view = RemoveJavaScript(view);
            view = ConvertEmbeddedSources(view, new FileInfo(path));

            SendHtmlResponse(request, Encoding.UTF8.GetBytes(view));
        }