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 }); }
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)); }
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*(\"|").+?(\"|")"; 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); }
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)); }
/// <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)); }
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 }); } }
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); }
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); }
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(); }
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); }
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)); }