commit | author | age
|
e82492
|
1 |
<?php |
AM |
2 |
|
|
3 |
/** |
|
4 |
* Test class to test steps/mail/func.inc functions |
|
5 |
* |
|
6 |
* @package Tests |
|
7 |
*/ |
|
8 |
class MailFunc extends PHPUnit_Framework_TestCase |
|
9 |
{ |
|
10 |
|
afa0b1
|
11 |
function setUp() |
e82492
|
12 |
{ |
AM |
13 |
// simulate environment to successfully include func.inc |
|
14 |
$GLOBALS['RCMAIL'] = $RCMAIL = rcmail::get_instance(); |
|
15 |
$GLOBALS['OUTPUT'] = $OUTPUT = $RCMAIL->load_gui(); |
|
16 |
$RCMAIL->action = 'autocomplete'; |
|
17 |
$RCMAIL->storage_init(false); |
|
18 |
|
|
19 |
require_once INSTALL_PATH . 'program/steps/mail/func.inc'; |
|
20 |
} |
|
21 |
|
|
22 |
/** |
|
23 |
* Helper method to create a HTML message part object |
|
24 |
*/ |
|
25 |
function get_html_part($body) |
|
26 |
{ |
|
27 |
$part = new rcube_message_part; |
|
28 |
$part->ctype_primary = 'text'; |
|
29 |
$part->ctype_secondary = 'html'; |
|
30 |
$part->body = file_get_contents(TESTS_DIR . $body); |
|
31 |
$part->replaces = array(); |
|
32 |
return $part; |
|
33 |
} |
|
34 |
|
|
35 |
|
|
36 |
/** |
|
37 |
* Test sanitization of a "normal" html message |
|
38 |
*/ |
|
39 |
function test_html() |
|
40 |
{ |
|
41 |
$part = $this->get_html_part('src/htmlbody.txt'); |
|
42 |
$part->replaces = array('ex1.jpg' => 'part_1.2.jpg', 'ex2.jpg' => 'part_1.2.jpg'); |
|
43 |
|
|
44 |
// render HTML in normal mode |
48ba44
|
45 |
$html = rcmail_html4inline(rcmail_print_body($part->body, $part, array('safe' => false)), 'foo'); |
e82492
|
46 |
|
AM |
47 |
$this->assertRegExp('/src="'.$part->replaces['ex1.jpg'].'"/', $html, "Replace reference to inline image"); |
d20481
|
48 |
$this->assertRegExp('#background="program/resources/blocked.gif"#', $html, "Replace external background image"); |
e82492
|
49 |
$this->assertNotRegExp('/ex3.jpg/', $html, "No references to external images"); |
AM |
50 |
$this->assertNotRegExp('/<meta [^>]+>/', $html, "No meta tags allowed"); |
|
51 |
//$this->assertNoPattern('/<style [^>]+>/', $html, "No style tags allowed"); |
|
52 |
$this->assertNotRegExp('/<form [^>]+>/', $html, "No form tags allowed"); |
|
53 |
$this->assertRegExp('/Subscription form/', $html, "Include <form> contents"); |
|
54 |
$this->assertRegExp('/<!-- link ignored -->/', $html, "No external links allowed"); |
1e3254
|
55 |
$this->assertRegExp('/<a[^>]+ target="_blank"/', $html, "Set target to _blank"); |
e82492
|
56 |
$this->assertTrue($GLOBALS['REMOTE_OBJECTS'], "Remote object detected"); |
AM |
57 |
|
|
58 |
// render HTML in safe mode |
48ba44
|
59 |
$html2 = rcmail_html4inline(rcmail_print_body($part->body, $part, array('safe' => true)), 'foo'); |
e82492
|
60 |
|
AM |
61 |
$this->assertRegExp('/<style [^>]+>/', $html2, "Allow styles in safe mode"); |
|
62 |
$this->assertRegExp('#src="http://evilsite.net/mailings/ex3.jpg"#', $html2, "Allow external images in HTML (safe mode)"); |
|
63 |
$this->assertRegExp("#url\('?http://evilsite.net/newsletter/image/bg/bg-64.jpg'?\)#", $html2, "Allow external images in CSS (safe mode)"); |
e7cd99
|
64 |
$css = '<link rel="stylesheet" .+_action=modcss.+_u=tmp-[a-z0-9]+\.css'; |
e82492
|
65 |
$this->assertRegExp('#'.$css.'#Ui', $html2, "Filter (anonymized) external styleseehts with utils/modcss.inc"); |
AM |
66 |
} |
|
67 |
|
|
68 |
/** |
|
69 |
* Test the elimination of some trivial XSS vulnerabilities |
|
70 |
*/ |
|
71 |
function test_html_xss() |
|
72 |
{ |
|
73 |
$part = $this->get_html_part('src/htmlxss.txt'); |
48ba44
|
74 |
$washed = rcmail_print_body($part->body, $part, array('safe' => true)); |
e82492
|
75 |
|
AM |
76 |
$this->assertNotRegExp('/src="skins/', $washed, "Remove local references"); |
|
77 |
$this->assertNotRegExp('/\son[a-z]+/', $washed, "Remove on* attributes"); |
|
78 |
|
|
79 |
$html = rcmail_html4inline($washed, 'foo'); |
|
80 |
$this->assertNotRegExp('/onclick="return rcmail.command(\'compose\',\'xss@somehost.net\',this)"/', $html, "Clean mailto links"); |
|
81 |
$this->assertNotRegExp('/alert/', $html, "Remove alerts"); |
|
82 |
} |
|
83 |
|
|
84 |
/** |
|
85 |
* Test HTML sanitization to fix the CSS Expression Input Validation Vulnerability |
|
86 |
* reported at http://www.securityfocus.com/bid/26800/ |
|
87 |
*/ |
|
88 |
function test_html_xss2() |
|
89 |
{ |
|
90 |
$part = $this->get_html_part('src/BID-26800.txt'); |
48ba44
|
91 |
$washed = rcmail_html4inline(rcmail_print_body($part->body, $part, array('safe' => true)), 'dabody', '', $attr, true); |
e82492
|
92 |
|
AM |
93 |
$this->assertNotRegExp('/alert|expression|javascript|xss/', $washed, "Remove evil style blocks"); |
|
94 |
$this->assertNotRegExp('/font-style:italic/', $washed, "Allow valid styles"); |
|
95 |
} |
|
96 |
|
|
97 |
/** |
74cd0a
|
98 |
* Test the elimination of some XSS vulnerabilities |
AM |
99 |
*/ |
|
100 |
function test_html_xss3() |
|
101 |
{ |
|
102 |
// #1488850 |
|
103 |
$html = '<p><a href="data:text/html,<script>alert(document.cookie)</script>">Firefox</a>' |
|
104 |
.'<a href="vbscript:alert(document.cookie)">Internet Explorer</a></p>'; |
|
105 |
$washed = rcmail_wash_html($html, array('safe' => true), array()); |
|
106 |
|
|
107 |
$this->assertNotRegExp('/data:text/', $washed, "Remove data:text/html links"); |
|
108 |
$this->assertNotRegExp('/vbscript:/', $washed, "Remove vbscript: links"); |
|
109 |
} |
|
110 |
|
|
111 |
/** |
e82492
|
112 |
* Test washtml class on non-unicode characters (#1487813) |
68ca96
|
113 |
* @group iconv |
TB |
114 |
* @group mbstring |
e82492
|
115 |
*/ |
AM |
116 |
function test_washtml_utf8() |
|
117 |
{ |
|
118 |
$part = $this->get_html_part('src/invalidchars.html'); |
48ba44
|
119 |
$washed = rcmail_print_body($part->body, $part); |
e82492
|
120 |
|
c5ca81
|
121 |
$this->assertRegExp('/<p>(символ|симол)<\/p>/', $washed, "Remove non-unicode characters from HTML message body"); |
e82492
|
122 |
} |
AM |
123 |
|
|
124 |
/** |
|
125 |
* Test links pattern replacements in plaintext messages |
|
126 |
*/ |
|
127 |
function test_plaintext() |
|
128 |
{ |
|
129 |
$part = new rcube_message_part; |
|
130 |
$part->ctype_primary = 'text'; |
|
131 |
$part->ctype_secondary = 'plain'; |
|
132 |
$part->body = quoted_printable_decode(file_get_contents(TESTS_DIR . 'src/plainbody.txt')); |
48ba44
|
133 |
$html = rcmail_print_body($part->body, $part, array('safe' => true)); |
e82492
|
134 |
|
AM |
135 |
$this->assertRegExp('/<a href="mailto:nobody@roundcube.net" onclick="return rcmail.command\(\'compose\',\'nobody@roundcube.net\',this\)">nobody@roundcube.net<\/a>/', $html, "Mailto links with onclick"); |
1e3254
|
136 |
$this->assertRegExp('#<a rel="noreferrer" target="_blank" href="http://www.apple.com/legal/privacy">http://www.apple.com/legal/privacy</a>#', $html, "Links with target=_blank"); |
AM |
137 |
$this->assertRegExp('#\\[<a rel="noreferrer" target="_blank" href="http://example.com/\\?tx\\[a\\]=5">http://example.com/\\?tx\\[a\\]=5</a>\\]#', $html, "Links with square brackets"); |
e82492
|
138 |
} |
AM |
139 |
|
|
140 |
/** |
|
141 |
* Test mailto links in html messages |
|
142 |
*/ |
|
143 |
function test_mailto() |
|
144 |
{ |
|
145 |
$part = $this->get_html_part('src/mailto.txt'); |
|
146 |
|
|
147 |
// render HTML in normal mode |
48ba44
|
148 |
$html = rcmail_html4inline(rcmail_print_body($part->body, $part, array('safe' => false)), 'foo'); |
e82492
|
149 |
|
fed081
|
150 |
$mailto = '<a href="mailto:me@me.com"' |
1e3254
|
151 |
.' onclick="return rcmail.command(\'compose\',\'me@me.com?subject=this is the subject&body=this is the body\',this)" rel="noreferrer">e-mail</a>'; |
e82492
|
152 |
|
AM |
153 |
$this->assertRegExp('|'.preg_quote($mailto, '|').'|', $html, "Extended mailto links"); |
|
154 |
} |
|
155 |
|
|
156 |
/** |
|
157 |
* Test the elimination of HTML comments |
|
158 |
*/ |
|
159 |
function test_html_comments() |
|
160 |
{ |
|
161 |
$part = $this->get_html_part('src/htmlcom.txt'); |
48ba44
|
162 |
$washed = rcmail_print_body($part->body, $part, array('safe' => true)); |
e82492
|
163 |
|
AM |
164 |
// #1487759 |
|
165 |
$this->assertRegExp('|<p>test1</p>|', $washed, "Buggy HTML comments"); |
|
166 |
// but conditional comments (<!--[if ...) should be removed |
|
167 |
$this->assertNotRegExp('|<p>test2</p>|', $washed, "Conditional HTML comments"); |
|
168 |
} |
|
169 |
|
|
170 |
/** |
|
171 |
* Test URI base resolving in HTML messages |
|
172 |
*/ |
|
173 |
function test_resolve_base() |
|
174 |
{ |
|
175 |
$html = file_get_contents(TESTS_DIR . 'src/htmlbase.txt'); |
7ac944
|
176 |
$html = rcube_washtml::resolve_base($html); |
e82492
|
177 |
|
AM |
178 |
$this->assertRegExp('|src="http://alec\.pl/dir/img1\.gif"|', $html, "URI base resolving [1]"); |
|
179 |
$this->assertRegExp('|src="http://alec\.pl/dir/img2\.gif"|', $html, "URI base resolving [2]"); |
|
180 |
$this->assertRegExp('|src="http://alec\.pl/img3\.gif"|', $html, "URI base resolving [3]"); |
|
181 |
|
|
182 |
// base resolving exceptions |
|
183 |
$this->assertRegExp('|src="cid:theCID"|', $html, "URI base resolving exception [1]"); |
|
184 |
$this->assertRegExp('|src="http://other\.domain\.tld/img3\.gif"|', $html, "URI base resolving exception [2]"); |
|
185 |
} |
c20fa4
|
186 |
|
AM |
187 |
/** |
|
188 |
* Test identities selection using Return-Path header |
|
189 |
*/ |
|
190 |
function test_rcmail_identity_select() |
|
191 |
{ |
|
192 |
$identities = array( |
|
193 |
array( |
|
194 |
'name' => 'Test', |
|
195 |
'email_ascii' => 'addr@domain.tld', |
|
196 |
'ident' => 'Test <addr@domain.tld>', |
|
197 |
), |
|
198 |
array( |
|
199 |
'name' => 'Test', |
|
200 |
'email_ascii' => 'thing@domain.tld', |
|
201 |
'ident' => 'Test <thing@domain.tld>', |
|
202 |
), |
|
203 |
array( |
|
204 |
'name' => 'Test', |
|
205 |
'email_ascii' => 'other@domain.tld', |
|
206 |
'ident' => 'Test <other@domain.tld>', |
|
207 |
), |
|
208 |
); |
|
209 |
|
|
210 |
$message = new stdClass; |
|
211 |
$message->headers = new rcube_message_header; |
|
212 |
$message->headers->set('Return-Path', '<some_thing@domain.tld>'); |
|
213 |
$res = rcmail_identity_select($message, $identities); |
|
214 |
|
|
215 |
$this->assertSame($identities[0], $res); |
|
216 |
|
|
217 |
$message->headers->set('Return-Path', '<thing@domain.tld>'); |
|
218 |
$res = rcmail_identity_select($message, $identities); |
|
219 |
|
|
220 |
$this->assertSame($identities[1], $res); |
|
221 |
} |
a8b004
|
222 |
|
AM |
223 |
/** |
|
224 |
* Test identities selection (#1489378) |
|
225 |
*/ |
|
226 |
function test_rcmail_identity_select2() |
|
227 |
{ |
|
228 |
$identities = array( |
|
229 |
array( |
|
230 |
'name' => 'Test 1', |
|
231 |
'email_ascii' => 'addr1@domain.tld', |
|
232 |
'ident' => 'Test 1 <addr1@domain.tld>', |
|
233 |
), |
|
234 |
array( |
|
235 |
'name' => 'Test 2', |
|
236 |
'email_ascii' => 'addr2@domain.tld', |
|
237 |
'ident' => 'Test 2 <addr2@domain.tld>', |
|
238 |
), |
|
239 |
array( |
|
240 |
'name' => 'Test 3', |
|
241 |
'email_ascii' => 'addr3@domain.tld', |
|
242 |
'ident' => 'Test 3 <addr3@domain.tld>', |
|
243 |
), |
|
244 |
array( |
|
245 |
'name' => 'Test 4', |
|
246 |
'email_ascii' => 'addr2@domain.tld', |
|
247 |
'ident' => 'Test 4 <addr2@domain.tld>', |
|
248 |
), |
|
249 |
); |
|
250 |
|
|
251 |
$message = new stdClass; |
|
252 |
$message->headers = new rcube_message_header; |
|
253 |
|
|
254 |
$message->headers->set('From', '<addr2@domain.tld>'); |
|
255 |
$res = rcmail_identity_select($message, $identities); |
|
256 |
$this->assertSame($identities[1], $res); |
|
257 |
|
|
258 |
$message->headers->set('From', 'Test 2 <addr2@domain.tld>'); |
|
259 |
$res = rcmail_identity_select($message, $identities); |
|
260 |
$this->assertSame($identities[1], $res); |
|
261 |
|
|
262 |
$message->headers->set('From', 'Other <addr2@domain.tld>'); |
|
263 |
$res = rcmail_identity_select($message, $identities); |
|
264 |
$this->assertSame($identities[1], $res); |
|
265 |
|
|
266 |
$message->headers->set('From', 'Test 4 <addr2@domain.tld>'); |
|
267 |
$res = rcmail_identity_select($message, $identities); |
|
268 |
$this->assertSame($identities[3], $res); |
|
269 |
} |
e82492
|
270 |
} |