From 4db85be4fe3fd92c73731a298724880edeaa85fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Schauer-K=C3=B6ckeis?= Date: Thu, 12 Sep 2024 14:55:28 +0200 Subject: [PATCH 1/4] Feat: Fix that Emails render all symbols right MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Schauer-Köckeis --- .../notification/publisher/DefaultNotificationPublishers.java | 2 +- .../notification/publisher/SendMailPublisher.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/dependencytrack/notification/publisher/DefaultNotificationPublishers.java b/src/main/java/org/dependencytrack/notification/publisher/DefaultNotificationPublishers.java index 85f49c7a38..3c5ee7c262 100644 --- a/src/main/java/org/dependencytrack/notification/publisher/DefaultNotificationPublishers.java +++ b/src/main/java/org/dependencytrack/notification/publisher/DefaultNotificationPublishers.java @@ -25,7 +25,7 @@ public enum DefaultNotificationPublishers { SLACK("Slack", "Publishes notifications to a Slack channel", SlackPublisher.class, "/templates/notification/publisher/slack.peb", MediaType.APPLICATION_JSON, true), MS_TEAMS("Microsoft Teams", "Publishes notifications to a Microsoft Teams channel", MsTeamsPublisher.class, "/templates/notification/publisher/msteams.peb", MediaType.APPLICATION_JSON, true), MATTERMOST("Mattermost", "Publishes notifications to a Mattermost channel", MattermostPublisher.class, "/templates/notification/publisher/mattermost.peb", MediaType.APPLICATION_JSON, true), - EMAIL("Email", "Sends notifications to an email address", SendMailPublisher.class, "/templates/notification/publisher/email.peb", MediaType.TEXT_PLAIN, true), + EMAIL("Email", "Sends notifications to an email address", SendMailPublisher.class, "/templates/notification/publisher/email.peb", "text/plain; charset=utf-8", true), CONSOLE("Console", "Displays notifications on the system console", ConsolePublisher.class, "/templates/notification/publisher/console.peb", MediaType.TEXT_PLAIN, true), WEBHOOK("Outbound Webhook", "Publishes notifications to a configurable endpoint", WebhookPublisher.class, "/templates/notification/publisher/webhook.peb", MediaType.APPLICATION_JSON, true), CS_WEBEX("Cisco Webex", "Publishes notifications to a Cisco Webex Teams channel", CsWebexPublisher.class, "/templates/notification/publisher/cswebex.peb", MediaType.APPLICATION_JSON, true), diff --git a/src/main/java/org/dependencytrack/notification/publisher/SendMailPublisher.java b/src/main/java/org/dependencytrack/notification/publisher/SendMailPublisher.java index 715313afe5..a515ca9b52 100644 --- a/src/main/java/org/dependencytrack/notification/publisher/SendMailPublisher.java +++ b/src/main/java/org/dependencytrack/notification/publisher/SendMailPublisher.java @@ -28,6 +28,8 @@ import alpine.server.mail.SendMailException; import io.pebbletemplates.pebble.PebbleEngine; import io.pebbletemplates.pebble.template.PebbleTemplate; + +import org.apache.commons.text.StringEscapeUtils; import org.dependencytrack.persistence.QueryManager; import org.dependencytrack.util.DebugDataEncryption; @@ -141,7 +143,7 @@ private void sendNotification(final PublishContext ctx, Notification notificatio .from(smtpFrom) .to(destinations) .subject(emailSubjectPrefix + " " + notification.getTitle()) - .body(content) + .body(StringEscapeUtils.unescapeHtml4(content)) .bodyMimeType(mimeType) .host(smtpHostname) .port(smtpPort) From 7f8cd640f65c6401cbf3dd3932ef6325a810e6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Schauer-K=C3=B6ckeis?= Date: Thu, 12 Sep 2024 15:44:26 +0200 Subject: [PATCH 2/4] Fixed test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Schauer-Köckeis --- .../publisher/DefaultNotificationPublishersTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/dependencytrack/notification/publisher/DefaultNotificationPublishersTest.java b/src/test/java/org/dependencytrack/notification/publisher/DefaultNotificationPublishersTest.java index 3718ba3bec..b125d50766 100644 --- a/src/test/java/org/dependencytrack/notification/publisher/DefaultNotificationPublishersTest.java +++ b/src/test/java/org/dependencytrack/notification/publisher/DefaultNotificationPublishersTest.java @@ -72,7 +72,7 @@ public void testEmail() { Assert.assertEquals("Sends notifications to an email address", DefaultNotificationPublishers.EMAIL.getPublisherDescription()); Assert.assertEquals(SendMailPublisher.class, DefaultNotificationPublishers.EMAIL.getPublisherClass()); Assert.assertEquals("/templates/notification/publisher/email.peb", DefaultNotificationPublishers.EMAIL.getPublisherTemplateFile()); - Assert.assertEquals(MediaType.TEXT_PLAIN, DefaultNotificationPublishers.EMAIL.getTemplateMimeType()); + Assert.assertEquals("text/plain; charset=utf-8", DefaultNotificationPublishers.EMAIL.getTemplateMimeType()); Assert.assertTrue(DefaultNotificationPublishers.EMAIL.isDefaultPublisher()); } From e61c561c264782c81184fa5d5d081aec3571abbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Schauer-K=C3=B6ckeis?= Date: Fri, 13 Sep 2024 10:16:14 +0200 Subject: [PATCH 3/4] Changed so, html rendering should also work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Schauer-Köckeis --- .../notification/publisher/SendMailPublisher.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/dependencytrack/notification/publisher/SendMailPublisher.java b/src/main/java/org/dependencytrack/notification/publisher/SendMailPublisher.java index a515ca9b52..c83c38fb65 100644 --- a/src/main/java/org/dependencytrack/notification/publisher/SendMailPublisher.java +++ b/src/main/java/org/dependencytrack/notification/publisher/SendMailPublisher.java @@ -35,6 +35,8 @@ import jakarta.json.JsonObject; import jakarta.json.JsonString; + +import jakarta.ws.rs.core.MediaType; import java.io.IOException; import java.util.Arrays; import java.util.Collections; @@ -137,13 +139,14 @@ private void sendNotification(final PublishContext ctx, Notification notificatio LOGGER.error("Failed to decrypt SMTP password (%s)".formatted(ctx), e); return; } + String unescapedContent = StringEscapeUtils.unescapeHtml4(content); try { final SendMail sendMail = new SendMail() .from(smtpFrom) .to(destinations) .subject(emailSubjectPrefix + " " + notification.getTitle()) - .body(StringEscapeUtils.unescapeHtml4(content)) + .body(mimeType == MediaType.TEXT_HTML ? StringEscapeUtils.escapeHtml4(unescapedContent): unescapedContent) .bodyMimeType(mimeType) .host(smtpHostname) .port(smtpPort) From 014ec6c1acfe6f86be56eb15313483cfaa2cc426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Schauer-K=C3=B6ckeis?= Date: Mon, 23 Sep 2024 08:45:55 +0200 Subject: [PATCH 4/4] Test for escaped Data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Schauer-Köckeis --- .../publisher/AbstractPublisherTest.java | 14 +++++++++ .../publisher/SendMailPublisherTest.java | 31 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/test/java/org/dependencytrack/notification/publisher/AbstractPublisherTest.java b/src/test/java/org/dependencytrack/notification/publisher/AbstractPublisherTest.java index 1f46b1b45f..cba787320c 100644 --- a/src/test/java/org/dependencytrack/notification/publisher/AbstractPublisherTest.java +++ b/src/test/java/org/dependencytrack/notification/publisher/AbstractPublisherTest.java @@ -215,6 +215,20 @@ public void testInformWithProjectAuditChangeNotification() { .isThrownBy(() -> publisherInstance.inform(PublishContext.from(notification), notification, createConfig())); } + @Test + public void testInformWithEscapedData() { + final var notification = new Notification() + .scope(NotificationScope.SYSTEM) + .group(NotificationGroup.ANALYZER) + .title(NotificationConstants.Title.NOTIFICATION_TEST) + .content("! \" § $ % & / ( ) = ? \\ ' * Ö Ü Ä ®️") + .level(NotificationLevel.ERROR) + .timestamp(LocalDateTime.ofEpochSecond(66666, 666, ZoneOffset.UTC)); + + assertThatNoException() + .isThrownBy(() -> publisherInstance.inform(PublishContext.from(notification), notification, createConfig())); + } + private static Component createComponent(final Project project) { final var component = new Component(); component.setProject(project); diff --git a/src/test/java/org/dependencytrack/notification/publisher/SendMailPublisherTest.java b/src/test/java/org/dependencytrack/notification/publisher/SendMailPublisherTest.java index 192578f1af..1388ac4540 100644 --- a/src/test/java/org/dependencytrack/notification/publisher/SendMailPublisherTest.java +++ b/src/test/java/org/dependencytrack/notification/publisher/SendMailPublisherTest.java @@ -395,6 +395,37 @@ public void testInformWithProjectAuditChangeNotification() { }); } + @Override + public void testInformWithEscapedData() { + super.testInformWithEscapedData(); + + assertThat(greenMail.getReceivedMessages()).satisfiesExactly(message -> { + assertThat(message.getSubject()).isEqualTo("[Dependency-Track] Notification Test"); + assertThat(message.getContent()).isInstanceOf(MimeMultipart.class); + final MimeMultipart content = (MimeMultipart) message.getContent(); + assertThat(content.getCount()).isEqualTo(1); + assertThat(content.getBodyPart(0)).isInstanceOf(MimeBodyPart.class); + assertThat((String) content.getBodyPart(0).getContent()).isEqualToIgnoringNewLines(""" + Notification Test + + -------------------------------------------------------------------------------- + + Level: ERROR + Scope: SYSTEM + Group: ANALYZER + + -------------------------------------------------------------------------------- + + ! " § $ % & / ( ) = ? \\ ' * Ö Ü Ä ®️ + + -------------------------------------------------------------------------------- + + 1970-01-01T18:31:06.000000666 + """); + }); + + } + @Override JsonObjectBuilder extraConfig() { return super.extraConfig()