From 8059ef5a4bf3e643fda6b39fe3a0808e60dfd109 Mon Sep 17 00:00:00 2001 From: Damiaan Peeters Date: Wed, 23 Aug 2023 12:31:43 +0200 Subject: [PATCH] Add an option to avoid tls certificate validation --- src/Seq.App.EmailPlus/DirectMailGateway.cs | 8 +++- src/Seq.App.EmailPlus/EmailApp.cs | 44 +++++++++++++--------- src/Seq.App.EmailPlus/SmtpOptions.cs | 1 + 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/Seq.App.EmailPlus/DirectMailGateway.cs b/src/Seq.App.EmailPlus/DirectMailGateway.cs index 17a2c7f..09e8499 100644 --- a/src/Seq.App.EmailPlus/DirectMailGateway.cs +++ b/src/Seq.App.EmailPlus/DirectMailGateway.cs @@ -12,7 +12,13 @@ public async Task SendAsync(SmtpOptions options, MimeMessage message) if (message == null) throw new ArgumentNullException(nameof(message)); var client = new SmtpClient(); - + + if (options.SkipCertificateValidation == true) + { + // WARNING: this bypasses certificate validation. + client.ServerCertificateValidationCallback = (s, c, h, e) => true; + } + await client.ConnectAsync(options.Host, options.Port, options.SocketOptions); if (options.RequiresAuthentication) await client.AuthenticateAsync(options.Username, options.Password); diff --git a/src/Seq.App.EmailPlus/EmailApp.cs b/src/Seq.App.EmailPlus/EmailApp.cs index b7d1863..5f1ffe9 100644 --- a/src/Seq.App.EmailPlus/EmailApp.cs +++ b/src/Seq.App.EmailPlus/EmailApp.cs @@ -79,6 +79,13 @@ public EmailApp() "implicit SSL will be enabled; otherwise, the STARTTLS extension will be used.")] public bool? EnableSsl { get; set; } + [SeqAppSetting( + IsOptional = true, + DisplayName = "Skip CertificateValidation", + HelpText = "This option allows you to have TLS enabled, but with an invalid certificate " + + "(expired, for another hostname, ...). Never use this in production.")] + public bool? SkipCertificateValidation { get; set; } + [SeqAppSetting( IsOptional = true, InputType = SettingInputType.LongText, @@ -104,7 +111,7 @@ public EmailApp() InputType = SettingInputType.Password, HelpText = "The password to use when authenticating to the SMTP server, if required.")] public string? Password { get; set; } - + [SeqAppSetting( DisplayName = "Time zone name", IsOptional = true, @@ -112,14 +119,14 @@ public EmailApp() "On Windows versions before Server 2019, and Seq versions before 2023.1, only Windows time zone " + "names are accepted.")] public string? TimeZoneName { get; set; } - + [SeqAppSetting( DisplayName = "Date/time format", IsOptional = true, HelpText = "A format string controlling how dates and times are formatted. Supports .NET date/time formatting " + "syntax. The default is `o`, producing ISO-8601.")] public string? DateTimeFormat { get; set; } - + protected override void OnAttached() { var port = Port ?? DefaultPort; @@ -130,13 +137,16 @@ protected override void OnAttached() ? RequireSslForPort(port) : SecureSocketOptions.StartTlsWhenAvailable, Username, - Password); + Password) + { + SkipCertificateValidation = SkipCertificateValidation ?? false, + }; - _subjectTemplate = Handlebars.Compile(string.IsNullOrEmpty(SubjectTemplate) - ? DefaultSubjectTemplate + _subjectTemplate = Handlebars.Compile(string.IsNullOrEmpty(SubjectTemplate) + ? DefaultSubjectTemplate : SubjectTemplate); - _bodyTemplate = Handlebars.Compile(string.IsNullOrEmpty(BodyTemplate) - ? Resources.DefaultBodyTemplate + _bodyTemplate = Handlebars.Compile(string.IsNullOrEmpty(BodyTemplate) + ? Resources.DefaultBodyTemplate : BodyTemplate); _toAddressesTemplate = string.IsNullOrEmpty(To) ? (_, _) => To : Handlebars.Compile(To); } @@ -146,7 +156,7 @@ public async Task OnAsync(Event evt) if (ShouldSuppress(evt)) return; var to = FormatTemplate(_toAddressesTemplate!, evt, base.Host) - .Split(new[]{','}, StringSplitOptions.RemoveEmptyEntries); + .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (to.Length == 0) { @@ -163,10 +173,10 @@ public async Task OnAsync(Event evt) await _mailGateway.SendAsync( _options, new MimeMessage( - new[] {MailboxAddress.Parse(From)}, + new[] { MailboxAddress.Parse(From) }, to.Select(MailboxAddress.Parse), subject, - new BodyBuilder {HtmlBody = body}.ToMessageBody())); + new BodyBuilder { HtmlBody = body }.ToMessageBody())); } bool ShouldSuppress(Event evt) @@ -207,10 +217,10 @@ internal static string FormatTemplate(Template template, Event evt { if (template == null) throw new ArgumentNullException(nameof(template)); if (evt == null) throw new ArgumentNullException(nameof(evt)); - - var properties = (IDictionary) ToDynamic(evt.Data.Properties ?? new Dictionary()); - var payload = (IDictionary) ToDynamic(new Dictionary + var properties = (IDictionary)ToDynamic(evt.Data.Properties ?? new Dictionary()); + + var payload = (IDictionary)ToDynamic(new Dictionary { { "$Id", evt.Id }, { "$UtcTimestamp", evt.TimestampUtc }, @@ -236,7 +246,7 @@ internal static string FormatTemplate(Template template, Event evt return template(payload); } - + string FormatTemplate(Template template, Event evt, Host host) { return FormatTemplate( @@ -246,7 +256,7 @@ string FormatTemplate(Template template, Event evt, Host host) string.IsNullOrEmpty(DateTimeFormat) ? "o" : DateTimeFormat!.Trim(), string.IsNullOrEmpty(TimeZoneName) ? PortableTimeZoneInfo.UtcTimeZoneName : TimeZoneName!.Trim()); } - + internal static string TestFormatTemplate(Template template, Event evt, Host host) { return FormatTemplate( @@ -262,7 +272,7 @@ static object ToDynamic(object o) if (o is IEnumerable> dictionary) { var result = new ExpandoObject(); - var asDict = (IDictionary) result; + var asDict = (IDictionary)result; foreach (var kvp in dictionary) asDict.Add(kvp.Key, ToDynamic(kvp.Value)); return result; diff --git a/src/Seq.App.EmailPlus/SmtpOptions.cs b/src/Seq.App.EmailPlus/SmtpOptions.cs index ec2d0c5..f1c2876 100644 --- a/src/Seq.App.EmailPlus/SmtpOptions.cs +++ b/src/Seq.App.EmailPlus/SmtpOptions.cs @@ -10,6 +10,7 @@ class SmtpOptions public string Username { get; } public string Password { get; } public SecureSocketOptions SocketOptions { get; } + public bool? SkipCertificateValidation { get; set; } public bool RequiresAuthentication => !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password);