Ejemplo n.º 1
0
        public async Task SendingEmailReplyFromTargetToDomainWithSpecialSubjectShouldSendAsDomainToExternalUserAndReplacePrivateMailInMetadataOfBody_WithSubjectPrefix()
        {
            var client = new Mock <ISendGridClient>();

            client.Setup(x => x.SendEmailAsync(It.IsAny <SendGridMessage>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new Response(System.Net.HttpStatusCode.Accepted, null, null));


            var logger = new Mock <ILogger>();
            var parser = new SubjectParser();
            var relay  = new RelayLogic(client.Object, parser, logger.Object, new[] { new OutlookWebSanitizer(parser) });

            await relay.RelayAsync(new Email
            {
                From = new EmailAddress
                {
                    Email = "*****@*****.**"
                },
                To = new[]
                {
                    new EmailAddress
                    {
                        Email = "*****@*****.**"
                    }
                },
                Text    = @"This is my response

___________________________________________
From: [email protected] <*****@*****.**>
Sent: Tuesday, September 3, 2019 11:19:42 PM
To: [email protected] <*****@*****.**>
Subject: RE: Relay for [email protected]: Test
 
This is the original message from someone",
                Subject = "RE: Relay for [email protected]: Test",
                Spf     = "pass",
                Dkim    = "{@live.com : pass}"
            }, "*****@*****.**", "domain.com", true, CancellationToken.None);

            client.Verify(x => x.SendEmailAsync(It.Is <SendGridMessage>(m =>
                                                                        m.From.Email == "*****@*****.**" &&
                                                                        m.Personalizations.Count == 1 &&
                                                                        m.Personalizations[0].Tos.Count == 1 &&
                                                                        m.Personalizations[0].Tos[0].Email == "*****@*****.**" &&
                                                                        m.Personalizations[0].Subject == "RE: Test" &&
                                                                        !m.Contents[0].Value.Contains("From: [email protected] <*****@*****.**>") &&
                                                                        !m.Contents[0].Value.Contains("To: [email protected] <*****@*****.**>") &&
                                                                        !m.Contents[0].Value.Contains("Subject: RE: Relay for [email protected]: Test") &&
                                                                        m.Contents[0].Value.Contains("From: [email protected] <*****@*****.**>") &&
                                                                        m.Contents[0].Value.Contains("To: [email protected] <*****@*****.**>") &&
                                                                        m.Contents[0].Value.Contains("Subject: RE: Test")),
                                                It.IsAny <CancellationToken>()));

            client.VerifyNoOtherCalls();
            logger.VerifyNoOtherCalls();
        }
Ejemplo n.º 2
0
        public async Task MailWithMultipleRecipientsShouldBeSentToFirstDomain()
        {
            var client = new Mock <ISendGridClient>();

            client.Setup(x => x.SendEmailAsync(It.IsAny <SendGridMessage>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new Response(System.Net.HttpStatusCode.Accepted, null, null));


            var logger = new Mock <ILogger>();
            var parser = new SubjectParser();
            var relay  = new RelayLogic(client.Object, parser, logger.Object, GetDefaultSanitizers());

            await relay.RelayAsync(new Email
            {
                From = new EmailAddress
                {
                    Email = "*****@*****.**"
                },
                To = new[]
                {
                    new EmailAddress
                    {
                        Email = "*****@*****.**"
                    },
                    new EmailAddress
                    {
                        Email = "*****@*****.**"
                    }
                },
                Cc = new[]
                {
                    new EmailAddress
                    {
                        Email = "*****@*****.**"
                    }
                },
                Html    = "Foo",
                Subject = "Inquiry"
            },
                                   "*****@*****.**",
                                   "domain.com",
                                   true,
                                   CancellationToken.None);

            client.Verify(x => x.SendEmailAsync(It.Is <SendGridMessage>(m =>
                                                                        m.From.Email == "*****@*****.**" &&
                                                                        m.Personalizations.Count == 1 &&
                                                                        m.Personalizations[0].Tos.Count == 1 &&
                                                                        m.Personalizations[0].Tos[0].Email == "*****@*****.**" &&
                                                                        m.Personalizations[0].Subject == "Relay for [email protected]: Inquiry"),
                                                It.IsAny <CancellationToken>()));

            client.VerifyNoOtherCalls();
            logger.VerifyNoOtherCalls();
        }
Ejemplo n.º 3
0
        public async Task SpecialSubjectFromSpoofedUserShouldBeLoggedAndNotSendFromDomain()
        {
            var client = new Mock <ISendGridClient>();

            client.Setup(x => x.SendEmailAsync(It.IsAny <SendGridMessage>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new Response(System.Net.HttpStatusCode.Accepted, null, null));


            var logger = new Mock <ILogger>();
            var parser = new SubjectParser();
            var relay  = new RelayLogic(client.Object, parser, logger.Object, GetDefaultSanitizers());

            await relay.RelayAsync(new Email
            {
                From = new EmailAddress
                {
                    Name  = "spoofed",
                    Email = "*****@*****.**"
                },
                To = new[]
                {
                    new EmailAddress
                    {
                        Email = "*****@*****.**"
                    }
                },
                Html    = "Foo",
                Subject = "Relay for [email protected]: Inquiry",
                Dkim    = "none",
                Spf     = "softfail"
            }, "*****@*****.**", "domain.com", true, CancellationToken.None);

            // external user should not be allowed to send as domain just by sending well crafted subject!
            // warning email must be issued to owner
            client.Verify(x => x.SendEmailAsync(It.Is <SendGridMessage>(m =>
                                                                        m.From.Email == "*****@*****.**" &&
                                                                        m.Personalizations.Count == 1 &&
                                                                        m.Personalizations[0].Tos.Count == 1 &&
                                                                        m.Personalizations[0].Tos[0].Email == "*****@*****.**" &&
                                                                        m.Personalizations[0].Subject == "[SPOOFWARNING] Relay for [email protected]: Inquiry" &&
                                                                        m.Contents[0].Value.Contains("Someone tried to send an email in the name of the domain")),
                                                It.IsAny <CancellationToken>()));
            logger.Verify(x => x.Log(LogLevel.Critical, It.IsAny <EventId>(), It.IsAny <object>(), null, It.IsAny <Func <object, Exception, string> >()));

            client.VerifyNoOtherCalls();
            logger.VerifyNoOtherCalls();
        }
Ejemplo n.º 4
0
        public async Task SendGridErrorShouldAbort()
        {
            var client = new Mock <ISendGridClient>();

            client.Setup(x => x.SendEmailAsync(It.IsAny <SendGridMessage>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new Response(System.Net.HttpStatusCode.BadRequest, new StringContent(JsonConvert.SerializeObject(new
            {
                error = "Sendgrid service unavailable"
            }), Encoding.UTF8, "application/json"), null));

            var logger = new Mock <ILogger>();
            var parser = new SubjectParser();
            var relay  = new RelayLogic(client.Object, parser, logger.Object, GetDefaultSanitizers());

            await new Func <Task>(async() => await relay.RelayAsync(new Email
            {
                From = new EmailAddress
                {
                    Email = "*****@*****.**"
                },
                To = new[]
                {
                    new EmailAddress
                    {
                        Email = "*****@*****.**"
                    }
                },
                Html    = "Foo",
                Subject = "Inquiry"
            },
                                                                    "*****@*****.**",
                                                                    "domain.com",
                                                                    true,
                                                                    CancellationToken.None))
            .Should().ThrowAsync <BadRequestException>();

            client.Verify(x => x.SendEmailAsync(It.Is <SendGridMessage>(m =>
                                                                        m.From.Email == "*****@*****.**" &&
                                                                        m.Personalizations.Count == 1 &&
                                                                        m.Personalizations[0].Tos.Count == 1 &&
                                                                        m.Personalizations[0].Tos[0].Email == "*****@*****.**" &&
                                                                        m.Personalizations[0].Subject == "Relay for [email protected]: Inquiry"),
                                                It.IsAny <CancellationToken>()));

            client.VerifyNoOtherCalls();
            logger.VerifyNoOtherCalls();
        }
Ejemplo n.º 5
0
        public async Task SendingEmailFromTargetToDomainWithSpecialSubjectShouldSendAsDomainToSelf()
        {
            var client = new Mock <ISendGridClient>();

            client.Setup(x => x.SendEmailAsync(It.IsAny <SendGridMessage>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new Response(System.Net.HttpStatusCode.Accepted, null, null));


            var logger = new Mock <ILogger>();
            var parser = new SubjectParser();
            var relay  = new RelayLogic(client.Object, parser, logger.Object, GetDefaultSanitizers());

            await relay.RelayAsync(new Email
            {
                From = new EmailAddress
                {
                    Email = "*****@*****.**"
                },
                To = new[]
                {
                    new EmailAddress
                    {
                        Email = "*****@*****.**"
                    }
                },
                Html    = "Foo",
                Subject = "Relay for [email protected]: Inquiry",
                Spf     = "pass",
                Dkim    = "{@privatemail.example.com : pass}"
            }, "*****@*****.**", "domain.com", true, CancellationToken.None);

            client.Verify(x => x.SendEmailAsync(It.Is <SendGridMessage>(m =>
                                                                        m.From.Email == "*****@*****.**" &&
                                                                        m.Personalizations.Count == 1 &&
                                                                        m.Personalizations[0].Tos.Count == 1 &&
                                                                        m.Personalizations[0].Tos[0].Email == "*****@*****.**" &&
                                                                        m.Personalizations[0].Subject == "Inquiry"),
                                                It.IsAny <CancellationToken>()));

            client.VerifyNoOtherCalls();
            logger.VerifyNoOtherCalls();
        }
Ejemplo n.º 6
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
            Microsoft.Azure.WebJobs.ExecutionContext context,
            ILogger log,
            CancellationToken cancellationToken)
        {
            try
            {
                var config = LoadConfig(context.FunctionAppDirectory, log);

                var container = config["ArchiveContainerName"];
                var target    = config["RelayTargetEmail"];
                if (string.IsNullOrEmpty(container) && string.IsNullOrEmpty(target))
                {
                    throw new NotSupportedException("Neither email target nor container name where set. Please set either ArchiveContainerName or RelayTargetEmail");
                }

                Email email;
                using (var stream = new MemoryStream())
                {
                    // body can only be read once
                    req.Body.CopyTo(stream);
                    stream.Position = 0;
                    var parser = new SendgridEmailParser();
                    email = parser.Parse(stream);
                }
                if (!string.IsNullOrEmpty(container))
                {
                    IPersister auditLogger = new BlobStoragePersister(config["AzureWebJobsStorage"], container);

                    var d = DateTimeOffset.UtcNow;
                    // one folder per day is fine for now
                    var id = $"{d.ToString("yyyy-MM")}/{d.ToString("dd")}/{d.ToString("HH-mm-ss")}_{email.From.Email} - {email.Subject}";
                    await auditLogger.PersistAsync($"{id}.json", JsonConvert.SerializeObject(email, Formatting.Indented));

                    // save all attachments in subfolder
                    await Task.WhenAll(email.Attachments.Select(a => auditLogger.PersistAsync($"{id} (Attachments)/{a.FileName}", Convert.FromBase64String(a.Base64Data))));
                }
                if (!string.IsNullOrEmpty(target))
                {
                    var domain = config["Domain"];
                    var key    = config["SendgridApiKey"];
                    if (!string.IsNullOrEmpty(target) &&
                        string.IsNullOrEmpty(domain))
                    {
                        throw new NotSupportedException("Domain must be set as well when relay is used.");
                    }
                    if (!string.IsNullOrEmpty(target) &&
                        string.IsNullOrEmpty(key))
                    {
                        throw new NotSupportedException("SendgridApiKey must be set as well when relay is used.");
                    }

                    var client        = new SendGridClient(key);
                    var subjectParser = new SubjectParser(config["Prefix"]);
                    var relay         = new RelayLogic(client, subjectParser, log, new[]
                    {
                        new OutlookWebSanitizer(subjectParser)
                    }
                                                       );
                    var sendAsDomain = "true".Equals(config["SendAsDomain"], StringComparison.OrdinalIgnoreCase);
                    await relay.RelayAsync(email, target, domain, sendAsDomain, cancellationToken);
                }

                return(new OkResult());
            }
            catch (Exception e)
            {
                log.LogCritical(e, "Failed to process request!");
                return(new BadRequestResult());
            }
        }