Skip to content

Commit 752b152

Browse files
authored
Check if attachment is actually(!) referred to (#9585)
* Check if "inline" msg part is actually referred to If there's no reference to it in a sibling HTML part then we handle it as a classic attachment (which is shown as downloadable). * Fetch all msg headers also for images to always get Content-Location Previously all headers were only fetched for message/rfc822, or if the Content-Type's "name" parameter was set, or if a Content-ID was set. The RFC doesn't require neither the "name" parameter nor a Content-ID for using Content-Location, though, so we shouldn't depend on those. Instead now all headers are also fetched if the main part of the Content-Type is "image", to catch more cases. * Parse HTML for references only on demand * Typos and comment formatting * Don't skip test anymore We want it tested! * More MR tests with images * Remove early special handling for "inline" images We decide later, which attachment is considered "inline" and which isn't. * Remove early resolving of references in TNEF parts * Testing message rendering of TNEF emails * Don't use image disposition, it's unreliable * Split adding raw parts and attachments * Fix renaming variable * Rename file to make its test be run * Remove outdated script * Annotate test cases with GitHub issue numbers * Fix test case class name * remove comment * Test inline image message rendering * Rename test file to reflect cases better * Reduce image used in test email It doesn't change much, but there's also no sense in decoding big images that we don't use. * Remove unused variable initialisation
1 parent 49d8639 commit 752b152

File tree

13 files changed

+2652
-131
lines changed

13 files changed

+2652
-131
lines changed

program/lib/Roundcube/rcube_imap.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2230,11 +2230,11 @@ protected function structure_part($part, $count = 0, $parent = '', $mime_headers
22302230
}
22312231
}
22322232

2233-
// fetch message headers if message/rfc822 or named part (could contain Content-Location header)
2233+
// fetch message headers if message/rfc822 or image or named part (could contain Content-Location header)
22342234
if (
22352235
empty($mime_headers)
22362236
&& (
2237-
$struct->ctype_primary == 'message'
2237+
$struct->ctype_primary == 'message' || $struct->ctype_primary == 'image'
22382238
|| (!empty($struct->ctype_parameters['name']) && !empty($struct->content_id))
22392239
)
22402240
) {

program/lib/Roundcube/rcube_message.php

Lines changed: 119 additions & 82 deletions
Large diffs are not rendered by default.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Tests\MessageRendering;
4+
5+
/**
6+
* Test class to test simple messages.
7+
*/
8+
class InlineImageTest extends MessageRenderingTestCase
9+
{
10+
public function testImageFromDataUri()
11+
{
12+
$domxpath = $this->runAndGetHtmlOutputDomxpath('trinity-eb9e559b-1926-4b09-990d-80e9da9a9c35-1723163091112@3c-app-mailcom-bs14');
13+
14+
$this->assertSame('***SPAM*** wir gratulieren Ihnen recht herzlich.', $this->getScrubbedSubject($domxpath));
15+
16+
$divElements = $domxpath->query('//div[@class="rcmBody"]/div/div');
17+
$this->assertCount(3, $divElements, 'Body HTML DIV elements');
18+
19+
$this->assertSame('wir gratulieren Ihnen recht herzlich.', $divElements[0]->textContent);
20+
21+
$img = $divElements[1]->firstChild->firstChild;
22+
$this->assertSame('img', $img->nodeName);
23+
$src = $img->attributes->getNamedItem('src')->textContent;
24+
$this->assertStringContainsString('?_task=mail&_action=get&_mbox=INBOX&_uid=', $src);
25+
$this->assertStringContainsString('&_part=2&_embed=1&_mimeclass=image', $src);
26+
27+
$this->assertSame('v1signature', $divElements[2]->attributes->getNamedItem('class')->textContent);
28+
// This matches a non-breakable space.
29+
$this->assertMatchesRegularExpression('|^\x{00a0}$|u', $divElements[2]->textContent);
30+
31+
$attchNames = $domxpath->query('//span[@class="attachment-name"]');
32+
$this->assertCount(0, $attchNames, 'Attachments');
33+
}
34+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Tests\MessageRendering;
4+
5+
/**
6+
* Test class to test "interesting" messages.
7+
*/
8+
class SingleAttachedImageNoTextTest extends MessageRenderingTestCase
9+
{
10+
/**
11+
* Test that of a multipart/mixed message which contains only one
12+
* image, that image is shown. (GitHub issue #9443)
13+
*/
14+
public function testShowMultipartMixedSingleImageToo()
15+
{
16+
$domxpath = $this->runAndGetHtmlOutputDomxpath('XXXXXXXXXXXXX@mx01.lytzenitmail.dk');
17+
18+
$this->assertSame('Not OK', $this->getScrubbedSubject($domxpath));
19+
20+
$attchNames = $domxpath->query('//span[@class="attachment-name"]');
21+
$this->assertCount(1, $attchNames, 'Attachments');
22+
$this->assertStringStartsWith('Resized_20240427_200026(1).jpeg', $attchNames[0]->textContent);
23+
}
24+
25+
/**
26+
* Test that an image, that has a Content-ID, which is not accompanied by
27+
* an HTML part (and thus is not referred to), is shown as attachment.
28+
* (GitHub issue #9565)
29+
*/
30+
public function testShowUnreferredToImagesWithContentId()
31+
{
32+
$domxpath = $this->runAndGetHtmlOutputDomxpath('yyy@mail.gmail.com');
33+
34+
$this->assertSame('test', $this->getScrubbedSubject($domxpath));
35+
36+
$attchNames = $domxpath->query('//span[@class="attachment-name"]');
37+
$this->assertCount(1, $attchNames, 'Attachments');
38+
$this->assertStringStartsWith('тест.jpg', $attchNames[0]->textContent);
39+
}
40+
41+
/**
42+
* Test that an image, that has a Content-ID, but is not referred to in the
43+
* accompanying HTML-part, is shown as attachment. (GitHub issue #9685)
44+
*/
45+
public function testShowUnreferredToImagesWithContentIdInMultipartAlternative()
46+
{
47+
$domxpath = $this->runAndGetHtmlOutputDomxpath('2ef37d1124655807449f5e405cdd4834b79fb026@example.net');
48+
49+
$this->assertSame('Multipart/alternative with attached but unreferenced image', $this->getScrubbedSubject($domxpath));
50+
51+
$attchNames = $domxpath->query('//span[@class="attachment-name"]');
52+
$this->assertCount(1, $attchNames, 'Attachments');
53+
$this->assertStringStartsWith('Stg Aiki - SB - 22-23 Fév 2025.jpg', $attchNames[0]->textContent);
54+
}
55+
}

tests/MessageRendering/SingleImageNoTextTest.php

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Tests\MessageRendering;
4+
5+
/**
6+
* Test class to test "interesting" messages.
7+
*/
8+
class TnefEmailsTest extends MessageRenderingTestCase
9+
{
10+
public function testTnefEmail1()
11+
{
12+
$domxpath = $this->runAndGetHtmlOutputDomxpath('631a672e15f742a98035f1cb7efe1f8db6310138@example.net');
13+
14+
$this->assertSame('', $this->getBody($domxpath));
15+
16+
$attchNames = $domxpath->query('//span[@class="attachment-name"]');
17+
$this->assertCount(1, $attchNames, 'Attachments');
18+
$this->assertStringStartsWith('AUTHORS', $attchNames[0]->textContent);
19+
}
20+
21+
public function testTnefEmail2()
22+
{
23+
$domxpath = $this->runAndGetHtmlOutputDomxpath('b6057653610f8041b120965652ff7f26a1a8f02d@example.net');
24+
25+
$this->assertStringStartsWith('THE BILL OF RIGHTSAmendments 1-10 of the', $this->getBody($domxpath));
26+
27+
$attchNames = $domxpath->query('//span[@class="attachment-name"]');
28+
$this->assertCount(0, $attchNames, 'Attachments');
29+
}
30+
31+
public function testTnefEmail3()
32+
{
33+
$domxpath = $this->runAndGetHtmlOutputDomxpath('cde7964538f283305609ec9146b4a80c121fd0ae@example.net');
34+
35+
$bodyParagraphs = $domxpath->query('//div[@class="rcmBody"]/p');
36+
$this->assertCount(8, $bodyParagraphs, 'Body HTML paragraphs');
37+
$this->assertSame('Casdasdfasdfasd', $bodyParagraphs[0]->textContent);
38+
$this->assertSame('Casdasdfasdfasd', $bodyParagraphs[1]->textContent);
39+
$this->assertSame('Casdasdfasdfasd', $bodyParagraphs[2]->textContent);
40+
$this->assertSame('Casdasdfasdfasd', $bodyParagraphs[3]->textContent);
41+
$this->assertSame('Casdasdfasdfasd', $bodyParagraphs[4]->textContent);
42+
$this->assertSame(' ', $bodyParagraphs[5]->textContent);
43+
$this->assertSame('Casdasdfasdfasd', $bodyParagraphs[6]->textContent);
44+
$this->assertSame(' ', $bodyParagraphs[7]->textContent);
45+
46+
$attchNames = $domxpath->query('//span[@class="attachment-name"]');
47+
$this->assertCount(2, $attchNames, 'Attachments');
48+
$this->assertStringStartsWith('zappa_av1.jpg', $attchNames[0]->textContent);
49+
$this->assertStringStartsWith('bookmark.htm', $attchNames[1]->textContent);
50+
51+
$inlineShownImages = $domxpath->query('//p[@class="image-attachment"]/span[@class="image-filename"]');
52+
$this->assertCount(1, $inlineShownImages, 'Inline shown images');
53+
$this->assertSame('zappa_av1.jpg', $inlineShownImages[0]->textContent);
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
From: <someone@example.net>
2+
To: <aaa@bbb.cc>
3+
Date: Wed, 1 Jul 2024 12:00:00 +0000
4+
Subject: Multipart/alternative with attached but unreferenced image
5+
Message-Id: <2ef37d1124655807449f5e405cdd4834b79fb026@example.net>
6+
Content-Type: multipart/mixed; boundary="00000000000000f0c80629385fe7"
7+
8+
--00000000000000f0c80629385fe7
9+
Content-Type: multipart/alternative; boundary="00000000000000f0c30629385fe5"
10+
11+
--00000000000000f0c30629385fe5
12+
Content-Type: text/plain; charset="UTF-8"
13+
Content-Transfer-Encoding: quoted-printable
14+
15+
Hugs !
16+
17+
---------- Forwarded message ---------
18+
De : Sender name <sender.name@gmail.com>
19+
Date: ven. 13 d=C3=A9c. 2024 =C3=A0 20:58
20+
Subject: Stage 222 23 f=C3=A9vrier 2025
21+
To: Recipient name <recipient.name@gmail.com>
22+
23+
--=20
24+
=E7=84=A1=E5=BE=97=E4=BC=9A INTERNATIONAL ADDRESS: http://mywebsite.org
25+
26+
"Bienheureux les f=C3=AAl=C3=A9s, car ils laisseront passer la lumi=C3=A8re=
27+
. "
28+
Michel Audiard=EF=BB=BF
29+
30+
--00000000000000f0c30629385fe5
31+
Content-Type: text/html; charset="UTF-8"
32+
Content-Transfer-Encoding: quoted-printable
33+
34+
<div dir=3D"ltr"><div class=3D"gmail_default" style=3D"font-family:verdana,=
35+
sans-serif;font-size:large">Hugs !<br></div><br><div class=3D"gmail_quote g=
36+
mail_quote_container"><div dir=3D"ltr" class=3D"gmail_attr">---------- Forw=
37+
arded message ---------<br>De=C2=A0: <b class=3D"gmail_sendername" dir=3D"a=
38+
uto">Sender Name</b> <span dir=3D"auto">&lt;<a href=3D"mailto:sender=
39+
.name@gmail.com">sender.mail@gmail.com</a>&gt=
40+
;</span><br>Date: ven. 13 d=C3=A9c. 2024 =C3=A0=C2=A020:58<br>Subject: Stag=
41+
e 222 23 f=C3=A9vrier 2025<br>To: Previuos recipient &lt;<a href=
42+
=3D"mailto:recipient@gmail.com">recipient@gmail.com</a>&gt;<br></div><br><b=
43+
r><div dir=3D"ltr"><br></div>
44+
</div><div><br clear=3D"all"></div><br><span class=3D"gmail_signature_prefi=
45+
x">-- </span><br><div dir=3D"ltr" class=3D"gmail_signature" data-smartmail=
46+
=3D"gmail_signature">=E7=84=A1=E5=BE=97=E4=BC=9A =C2=A0INTERNATIONAL ADDRES=
47+
S: <a href=3D"http://mywebsite.org" target=3D"_blank">http://mywebsite.org<=
48+
/a><br><br>&quot;Bienheureux les f=C3=AAl=C3=A9s, car ils laisseront passer=
49+
la lumi=C3=A8re.=C2=A0&quot;<br>Michel Audiard=EF=BB=BF<br><br><br><br><br=
50+
><br><br></div></div>
51+
52+
--00000000000000f0c30629385fe5--
53+
--00000000000000f0c80629385fe7
54+
Content-Type: image/jpeg; name="=?UTF-8?B?U3RnIEFpa2kgLSBTQiAtIDIyLTIzIEZlzIF2IDIwMjUu?=
55+
=?UTF-8?B?anBn?="
56+
Content-Disposition: attachment;
57+
filename="=?UTF-8?B?U3RnIEFpa2kgLSBTQiAtIDIyLTIzIEZlzIF2IDIwMjUuanBn?="
58+
Content-Transfer-Encoding: base64
59+
Content-ID: <f_m4n674et0>
60+
X-Attachment-Id: f_m4n674et0
61+
62+
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
129+
LkOqP//Z
130+
--00000000000000f0c80629385fe7--
131+

0 commit comments

Comments
 (0)