From 64222e3311041ac489e106b9798d50b8dc7513b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Wed, 4 Oct 2023 09:12:52 +0200 Subject: [PATCH] Fix handling of unquoted images src in mail collector fixes #15578 --- src/Ticket.php | 18 ++-- .../41-image-src-with-no-quote.eml | 41 +++++++++ tests/functional/Ticket.php | 83 ++++++++++++------- tests/imap/MailCollector.php | 2 + 4 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 tests/emails-tests/41-image-src-with-no-quote.eml diff --git a/src/Ticket.php b/src/Ticket.php index e632ed6067b..f6a42856145 100644 --- a/src/Ticket.php +++ b/src/Ticket.php @@ -6189,16 +6189,18 @@ public function getRights($interface = 'central') **/ public static function convertContentForTicket($html, $files, $tags) { - - preg_match_all("/src\s*=\s*['|\"](.+?)['|\"]/", $html, $matches, PREG_PATTERN_ORDER); - if (isset($matches[1]) && count($matches[1])) { - // Get all image src - - foreach ($matches[1] as $src) { + $src_patterns = [ + 'src\s*=\s*"[^"]+"', // src="image.png" + "src\s*=\s*'[^']+'", // src='image.png' + 'src\s*=[^\s>]+', // src=image.png + ]; + $matches = []; + if (preg_match_all('/(' . implode('|', $src_patterns) . ')/', $html, $matches, PREG_PATTERN_ORDER) > 0) { + foreach ($matches[0] as $src_attr) { // Set tag if image matches foreach ($files as $data => $filename) { - if (preg_match("/" . $data . "/i", $src)) { - $html = preg_replace("/]*src=['|\"]" . preg_quote($src, '/') . "['|\"][^>]*\>/s", "

" . Document::getImageTag($tags[$filename]) . "

", $html); + if (preg_match("/" . $data . "/i", $src_attr)) { + $html = preg_replace("/]*" . preg_quote($src_attr, '/') . "[^>]*>/s", "

" . Document::getImageTag($tags[$filename]) . "

", $html); } } } diff --git a/tests/emails-tests/41-image-src-with-no-quote.eml b/tests/emails-tests/41-image-src-with-no-quote.eml new file mode 100644 index 00000000000..0ad46464f5a --- /dev/null +++ b/tests/emails-tests/41-image-src-with-no-quote.eml @@ -0,0 +1,41 @@ +Date: Thu, 1 Dec 2022 11:23:48 +0200 (CEST) +From: Normal User +To: GLPI debug +Subject: 41 - Image src without quotes +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="----=_Part_1757883_1359581901.1528365951028" + +------=_Part_1757883_1359581901.1528365951028 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit + +Image: + +------=_Part_1757883_1359581901.1528365951028 +Content-Type: multipart/related; + boundary="----=_Part_1757884_1267006027.1528365951028" + +------=_Part_1757884_1267006027.1528365951028 +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: 7bit + + + +Image: + + +------=_Part_1757884_1267006027.1528365951028 +Content-Type: image/png; name=41-blue-dot.png +Content-Disposition: attachment; filename=41-blue-dot.png +Content-Transfer-Encoding: base64 +Content-ID: + +iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAAXNSR0IB2cksfwAAAAlwSFlzAAAL +EwAACxMBAJqcGAAAAANQTFRFAAD/injSVwAAAApJREFUeJxjYAAAAAIAAUivpHEAAAAASUVORK5C +YII= +------=_Part_1757884_1267006027.1528365951028-- + +------=_Part_1757883_1359581901.1528365951028-- + + diff --git a/tests/functional/Ticket.php b/tests/functional/Ticket.php index 682f6e8ddf5..daee1f0f955 100644 --- a/tests/functional/Ticket.php +++ b/tests/functional/Ticket.php @@ -4230,51 +4230,74 @@ protected function convertContentForTicketProvider(): iterable 'expected' => '', ]; - // Content with embedded image. - yield [ - 'content' => << << + blabla HTML - , - 'files' => [ - 'screenshot.png' => 'screenshot.png', - ], - 'tags' => [ - 'screenshot.png' => '9faff0a6-f37490bd-60e2af9721f420.96500246', - ], - 'expected' => << [ + 'screenshot.png' => 'screenshot.png', + ], + 'tags' => [ + 'screenshot.png' => '9faff0a6-f37490bd-60e2af9721f420.96500246', + ], + 'expected' => <<#9faff0a6-f37490bd-60e2af9721f420.96500246#

blabla HTML - , - ]; + , + ]; + // `img` of embedded image that has multiple attributes. + yield [ + 'content' => << +blabla +HTML + , + 'files' => [ + 'screenshot.png' => 'screenshot.png', + ], + 'tags' => [ + 'screenshot.png' => '9faff0a6-f37490bd-60e2af9721f420.96500246', + ], + 'expected' => <<#9faff0a6-f37490bd-60e2af9721f420.96500246#

+blabla +HTML + , + ]; - // Content with leading external image that will not be replaced by a tag. - yield [ - 'content' => << + // Content with leading external image that will not be replaced by a tag. + yield [ + 'content' => << Here is the screenshot: - + blabla HTML - , - 'files' => [ - 'img.jpg' => 'img.jpg', - ], - 'tags' => [ - 'img.jpg' => '3eaff0a6-f37490bd-60e2a59721f420.96500246', - ], - 'expected' => << + , + 'files' => [ + 'img.jpg' => 'img.jpg', + ], + 'tags' => [ + 'img.jpg' => '3eaff0a6-f37490bd-60e2a59721f420.96500246', + ], + 'expected' => << Here is the screenshot:

#3eaff0a6-f37490bd-60e2a59721f420.96500246#

blabla HTML - , - ]; + , + ]; + } } /** diff --git a/tests/imap/MailCollector.php b/tests/imap/MailCollector.php index 2792c7ec989..8bfc17decd7 100644 --- a/tests/imap/MailCollector.php +++ b/tests/imap/MailCollector.php @@ -791,6 +791,7 @@ function () use (&$msg) { '40.1 - Empty content (multipart)', '40.2 - Empty content (html)', '40.3 - Empty content (plain text)', + '41 - Image src without quotes', ] ], // Mails having "normal" user as observer (add_cc_to_observer = true) @@ -943,6 +944,7 @@ function () use (&$msg) { '1234567890_2' => 'text/plain', '1234567890_3' => 'text/plain', '37-red-dot.png' => 'image/png', + '41-blue-dot.png' => 'image/png', ]; $iterator = $DB->request(