|
|
@ -348,25 +348,24 @@ class Actions_Mail_Index extends ActionTestCase |
|
|
|
$part = $this->get_html_part('src/htmlbody.txt'); |
|
|
|
$part->replaces = ['ex1.jpg' => 'part_1.2.jpg', 'ex2.jpg' => 'part_1.2.jpg']; |
|
|
|
|
|
|
|
$params = ['container_id' => 'foo']; |
|
|
|
$params = ['container_id' => 'foo', 'safe' => false]; |
|
|
|
|
|
|
|
// render HTML in normal mode
|
|
|
|
$body = rcmail_action_mail_index::print_body($part->body, $part, ['safe' => false]); |
|
|
|
$html = rcmail_action_mail_index::html4inline($body, $params); |
|
|
|
|
|
|
|
$this->assertRegExp('/src="'.$part->replaces['ex1.jpg'].'"/', $html, "Replace reference to inline image"); |
|
|
|
$this->assertRegExp('#background="program/resources/blocked.gif"#', $html, "Replace external background image"); |
|
|
|
$this->assertNotRegExp('/ex3.jpg/', $html, "No references to external images"); |
|
|
|
$this->assertNotRegExp('/<meta [^>]+>/', $html, "No meta tags allowed"); |
|
|
|
$this->assertNotRegExp('/<form [^>]+>/', $html, "No form tags allowed"); |
|
|
|
$this->assertRegExp('/Subscription form/', $html, "Include <form> contents"); |
|
|
|
$this->assertRegExp('/<!-- link ignored -->/', $html, "No external links allowed"); |
|
|
|
$this->assertRegExp('/<a[^>]+ target="_blank"/', $html, "Set target to _blank"); |
|
|
|
$html = \rcmail_action_mail_index::print_body($part->body, $part, $params); |
|
|
|
|
|
|
|
$this->assertMatchesRegularExpression('/src="'.$part->replaces['ex1.jpg'].'"/', $html, "Replace reference to inline image"); |
|
|
|
$this->assertMatchesRegularExpression('#background="program/resources/blocked.gif"#', $html, "Replace external background image"); |
|
|
|
$this->assertDoesNotMatchRegularExpression('/ex3.jpg/', $html, "No references to external images"); |
|
|
|
$this->assertDoesNotMatchRegularExpression('/<meta [^>]+>/', $html, "No meta tags allowed"); |
|
|
|
$this->assertDoesNotMatchRegularExpression('/<form [^>]+>/', $html, "No form tags allowed"); |
|
|
|
$this->assertMatchesRegularExpression('/Subscription form/', $html, "Include <form> contents"); |
|
|
|
$this->assertMatchesRegularExpression('/<!-- link ignored -->/', $html, "No external links allowed"); |
|
|
|
$this->assertMatchesRegularExpression('/<a[^>]+ target="_blank"/', $html, "Set target to _blank"); |
|
|
|
// $this->assertTrue($GLOBALS['REMOTE_OBJECTS'], "Remote object detected");
|
|
|
|
|
|
|
|
// render HTML in safe mode
|
|
|
|
$body = rcmail_action_mail_index::print_body($part->body, $part, ['safe' => true]); |
|
|
|
$html = rcmail_action_mail_index::html4inline($body, $params); |
|
|
|
$params['safe'] = true; |
|
|
|
$html = \rcmail_action_mail_index::print_body($part->body, $part, $params); |
|
|
|
|
|
|
|
$this->assertRegExp('/<style [^>]+>/', $html, "Allow styles in safe mode"); |
|
|
|
$this->assertRegExp('#src="http://evilsite.net/mailings/ex3.jpg"#', $html, "Allow external images in HTML (safe mode)"); |
|
|
@ -383,17 +382,14 @@ class Actions_Mail_Index extends ActionTestCase |
|
|
|
$this->initOutput(rcmail_action::MODE_HTTP, 'mail', ''); |
|
|
|
|
|
|
|
$part = $this->get_html_part('src/htmlxss.txt'); |
|
|
|
$washed = rcmail_action_mail_index::print_body($part->body, $part, ['safe' => true]); |
|
|
|
|
|
|
|
$this->assertNotRegExp('/src="skins/', $washed, "Remove local references"); |
|
|
|
$this->assertNotRegExp('/\son[a-z]+/', $washed, "Remove on* attributes"); |
|
|
|
$this->assertNotContains('onload', $washed, "Handle invalid style"); |
|
|
|
$params = ['container_id' => 'foo', 'safe' => true]; |
|
|
|
$html = \rcmail_action_mail_index::print_body($part->body, $part, $params); |
|
|
|
|
|
|
|
$params = ['container_id' => 'foo']; |
|
|
|
$html = rcmail_action_mail_index::html4inline($washed, $params); |
|
|
|
|
|
|
|
$this->assertNotRegExp('/onclick="return rcmail.command(\'compose\',\'xss@somehost.net\',this)"/', $html, "Clean mailto links"); |
|
|
|
$this->assertNotRegExp('/alert/', $html, "Remove alerts"); |
|
|
|
$this->assertDoesNotMatchRegularExpression('/src="skins/', $html, 'Remove local references'); |
|
|
|
$this->assertDoesNotMatchRegularExpression('/\son[a-z]+/', $html, 'Remove on* attributes'); |
|
|
|
$this->assertStringNotContainsString('onload', $html, 'Handle invalid style'); |
|
|
|
$this->assertDoesNotMatchRegularExpression('/onclick="return rcmail.command(\'compose\',\'xss@somehost.net\',this)"/', $html, "Clean mailto links"); |
|
|
|
$this->assertDoesNotMatchRegularExpression('/alert/', $html, "Remove alerts"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -406,8 +402,7 @@ class Actions_Mail_Index extends ActionTestCase |
|
|
|
|
|
|
|
$part = $this->get_html_part('src/BID-26800.txt'); |
|
|
|
$params = ['container_id' => 'dabody', 'safe' => true]; |
|
|
|
$body = rcmail_action_mail_index::print_body($part->body, $part, ['safe' => true]); |
|
|
|
$washed = rcmail_action_mail_index::html4inline($body, $params); |
|
|
|
$washed = \rcmail_action_mail_index::print_body($part->body, $part, $params); |
|
|
|
|
|
|
|
$this->assertNotRegExp('/alert|expression|javascript|xss/', $washed, "Remove evil style blocks"); |
|
|
|
$this->assertNotRegExp('/font-style:italic/', $washed, "Allow valid styles"); |
|
|
@ -429,20 +424,40 @@ class Actions_Mail_Index extends ActionTestCase |
|
|
|
$this->assertNotRegExp('/vbscript:/', $washed, "Remove vbscript: links"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Test that HTML sanitization does not change attribute (evil) values |
|
|
|
*/ |
|
|
|
public function test_html_body_attributes() |
|
|
|
{ |
|
|
|
$part = $this->get_html_part(); |
|
|
|
$part->body = '<body title="bgcolor=foo" name="bar style=animation-name:progress-bar-stripes onanimationstart=alert(origin) foo=bar">Foo</body>'; |
|
|
|
|
|
|
|
$params = ['safe' => true, 'add_comments' => false]; |
|
|
|
$washed = \rcmail_action_mail_index::print_body($part->body, $part, $params); |
|
|
|
|
|
|
|
$this->assertSame(str_replace('body', 'div', $part->body), $washed); |
|
|
|
|
|
|
|
$params['inline_html'] = false; |
|
|
|
$washed = \rcmail_action_mail_index::print_body($part->body, $part, $params); |
|
|
|
|
|
|
|
$this->assertSame('<html><head></head>' . $part->body . '</html>', $washed); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Test handling of body style attributes |
|
|
|
*/ |
|
|
|
function test_html4inline_body_style() |
|
|
|
public function test_wash_html_body_style() |
|
|
|
{ |
|
|
|
$html = '<body background="test" bgcolor="#fff" style="font-size:11px" text="#000"><p>test</p></body>'; |
|
|
|
$params = ['container_id' => 'foo']; |
|
|
|
$html = rcmail_action_mail_index::html4inline($html, $params); |
|
|
|
$html = '<body background="http://test.com/image" bgcolor="#fff" style="font-size: 11px" text="#000"><p>test</p></body>'; |
|
|
|
$params = ['container_id' => 'foo', 'add_comments' => false, 'safe' => false]; |
|
|
|
$washed = \rcmail_action_mail_index::wash_html($html, $params, []); |
|
|
|
|
|
|
|
$this->assertSame('<div id="foo" style="font-size: 11px; background-image: url(program/resources/blocked.gif); background-color: #fff; color: #000"><p>test</p></div>', $washed); |
|
|
|
|
|
|
|
$params['safe'] = true; |
|
|
|
$washed = \rcmail_action_mail_index::wash_html($html, $params, []); |
|
|
|
|
|
|
|
$this->assertRegExp('/<div style="font-size:11px">/', $html, "Body attributes"); |
|
|
|
$this->assertArrayHasKey('container_attrib', $params, "'container_attrib' param set"); |
|
|
|
$this->assertRegExp('/background-color: #fff;/', $params['container_attrib']['style'], "Body style (bgcolor)"); |
|
|
|
$this->assertRegExp('/background-image: url\(test\)/', $params['container_attrib']['style'], "Body style (background)"); |
|
|
|
$this->assertRegExp('/color: #000/', $params['container_attrib']['style'], "Body style (text)"); |
|
|
|
$this->assertSame('<div id="foo" style="font-size: 11px; background-image: url(http://test.com/image); background-color: #fff; color: #000"><p>test</p></div>', $washed); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@ -468,6 +483,7 @@ class Actions_Mail_Index extends ActionTestCase |
|
|
|
|
|
|
|
$meta = '<meta charset="'.RCUBE_CHARSET.'" />'; |
|
|
|
$args = [ |
|
|
|
'inline_html' => false, |
|
|
|
'html_elements' => ['html', 'body', 'meta', 'head'], |
|
|
|
'html_attribs' => ['charset'], |
|
|
|
]; |
|
|
@ -524,11 +540,10 @@ class Actions_Mail_Index extends ActionTestCase |
|
|
|
$this->initOutput(rcmail_action::MODE_HTTP, 'mail', ''); |
|
|
|
|
|
|
|
$part = $this->get_html_part('src/mailto.txt'); |
|
|
|
$params = ['container_id' => 'foo']; |
|
|
|
$params = ['container_id' => 'foo', 'safe' => false]; |
|
|
|
|
|
|
|
// render HTML in normal mode
|
|
|
|
$body = rcmail_action_mail_index::print_body($part->body, $part, ['safe' => false]); |
|
|
|
$html = rcmail_action_mail_index::html4inline($body, $params); |
|
|
|
$html = \rcmail_action_mail_index::print_body($part->body, $part, $params); |
|
|
|
|
|
|
|
$mailto = '<a href="mailto:me@me.com"' |
|
|
|
.' onclick="return rcmail.command(\'compose\',\'me@me.com?subject=this is the subject&body=this is the body\',this)" rel="noreferrer">e-mail</a>'; |
|
|
|