Add rel="noreferrer" for links in displayed messages (#1484686)
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Add rel="noreferrer" for links in displayed messages (#1484686) |
| | | - Fix so forward as attachment works if additional attachment is added by message_compose hook (#1489000) |
| | | - Add ability to toggle between HTML and text while viewing a message (#1486939) |
| | | - Better handling of session errors in ajax requests (#1488960) |
| | |
| | | public $mailto_pattern; |
| | | public $link_pattern; |
| | | private $values = array(); |
| | | private $options = array(); |
| | | |
| | | |
| | | function __construct() |
| | | function __construct($options = array()) |
| | | { |
| | | // Simplified domain expression for UTF8 characters handling |
| | | // Support unicode/punycode in top-level domain part |
| | |
| | | ."@$utf_domain" // domain-part |
| | | ."(\?[$url1$url2]+)?" // e.g. ?subject=test... |
| | | .")/"; |
| | | |
| | | $this->options = $options; |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | if ($url) { |
| | | $suffix = $this->parse_url_brackets($url); |
| | | $i = $this->add($prefix . html::a(array( |
| | | 'href' => $url_prefix . $url, |
| | | 'target' => '_blank' |
| | | ), rcube::Q($url)) . $suffix); |
| | | $attrib = (array)$this->options['link_attribs']; |
| | | $attrib['href'] = $url_prefix . $url; |
| | | |
| | | $i = $this->add($prefix . html::a($attrib, rcube::Q($url)) . $suffix); |
| | | } |
| | | |
| | | // Return valid link for recognized schemes, otherwise |
| | |
| | | global $RCMAIL; |
| | | |
| | | // make links and email-addresses clickable |
| | | $replacer = new rcmail_string_replacer; |
| | | $attribs = array('link_attribs' => array('rel' => 'noreferrer', 'target' => '_blank')); |
| | | $replacer = new rcmail_string_replacer($attribs); |
| | | |
| | | // search for patterns like links and e-mail addresses and replace with tokens |
| | | $body = $replacer->replace($body); |
| | |
| | | |
| | | |
| | | /** |
| | | * parse link attributes and set correct target |
| | | * parse link (a, link, area) attributes and set correct target |
| | | */ |
| | | function rcmail_alter_html_link($matches) |
| | | { |
| | |
| | | // Support unicode/punycode in top-level domain part |
| | | $EMAIL_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))'; |
| | | |
| | | $tag = $matches[1]; |
| | | $tag = strtolower($matches[1]); |
| | | $attrib = parse_attrib_string($matches[2]); |
| | | $end = '>'; |
| | | $end = '>'; |
| | | |
| | | // Remove non-printable characters in URL (#1487805) |
| | | if ($attrib['href']) |
| | |
| | | $attrib['target'] = '_blank'; |
| | | } |
| | | |
| | | // Better security by adding rel="noreferrer" (#1484686) |
| | | if (($tag == 'a' || $tag == 'area') && $attrib['href'] && $attrib['href'][0] != '#') { |
| | | $attrib['rel'] = 'noreferrer'; |
| | | } |
| | | |
| | | // allowed attributes for a|link|area tags |
| | | $allow = array('href','name','target','onclick','id','class','style','title', |
| | | 'rel','type','media','alt','coords','nohref','hreflang','shape'); |
| | |
| | | function data_replace() |
| | | { |
| | | return array( |
| | | array('http://domain.tld/path*path2', '<a href="http://domain.tld/path*path2" target="_blank">http://domain.tld/path*path2</a>'), |
| | | array("Click this link:\nhttps://mail.xn--brderli-o2a.ch/rc/ EOF", "Click this link:\n<a href=\"https://mail.xn--brderli-o2a.ch/rc/\" target=\"_blank\">https://mail.xn--brderli-o2a.ch/rc/</a> EOF"), |
| | | array('Start http://localhost/?foo End', 'Start <a href="http://localhost/?foo" target="_blank">http://localhost/?foo</a> End'), |
| | | array('www.domain.tld', '<a href="http://www.domain.tld" target="_blank">www.domain.tld</a>'), |
| | | array('WWW.DOMAIN.TLD', '<a href="http://WWW.DOMAIN.TLD" target="_blank">WWW.DOMAIN.TLD</a>'), |
| | | array('[http://link.com]', '[<a href="http://link.com" target="_blank">http://link.com</a>]'), |
| | | array('http://link.com?a[]=1', '<a href="http://link.com?a[]=1" target="_blank">http://link.com?a[]=1</a>'), |
| | | array('http://link.com?a[]', '<a href="http://link.com?a[]" target="_blank">http://link.com?a[]</a>'), |
| | | array('(http://link.com)', '(<a href="http://link.com" target="_blank">http://link.com</a>)'), |
| | | array('http://link.com?a(b)c', '<a href="http://link.com?a(b)c" target="_blank">http://link.com?a(b)c</a>'), |
| | | array('http://link.com?(link)', '<a href="http://link.com?(link)" target="_blank">http://link.com?(link)</a>'), |
| | | array('http://domain.tld/path*path2', '<a href="http://domain.tld/path*path2">http://domain.tld/path*path2</a>'), |
| | | array("Click this link:\nhttps://mail.xn--brderli-o2a.ch/rc/ EOF", "Click this link:\n<a href=\"https://mail.xn--brderli-o2a.ch/rc/\">https://mail.xn--brderli-o2a.ch/rc/</a> EOF"), |
| | | array('Start http://localhost/?foo End', 'Start <a href="http://localhost/?foo">http://localhost/?foo</a> End'), |
| | | array('www.domain.tld', '<a href="http://www.domain.tld">www.domain.tld</a>'), |
| | | array('WWW.DOMAIN.TLD', '<a href="http://WWW.DOMAIN.TLD">WWW.DOMAIN.TLD</a>'), |
| | | array('[http://link.com]', '[<a href="http://link.com">http://link.com</a>]'), |
| | | array('http://link.com?a[]=1', '<a href="http://link.com?a[]=1">http://link.com?a[]=1</a>'), |
| | | array('http://link.com?a[]', '<a href="http://link.com?a[]">http://link.com?a[]</a>'), |
| | | array('(http://link.com)', '(<a href="http://link.com">http://link.com</a>)'), |
| | | array('http://link.com?a(b)c', '<a href="http://link.com?a(b)c">http://link.com?a(b)c</a>'), |
| | | array('http://link.com?(link)', '<a href="http://link.com?(link)">http://link.com?(link)</a>'), |
| | | array('http://<test>', 'http://<test>'), |
| | | array('http://', 'http://'), |
| | | ); |
| | |
| | | $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"); |
| | | $this->assertRegExp('/<a[^>]+ target="_blank"/', $html, "Set target to _blank"); |
| | | $this->assertTrue($GLOBALS['REMOTE_OBJECTS'], "Remote object detected"); |
| | | |
| | | // render HTML in safe mode |
| | |
| | | $html = rcmail_print_body($part, array('safe' => true)); |
| | | |
| | | $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"); |
| | | $this->assertRegExp('#<a href="http://www.apple.com/legal/privacy" target="_blank">http://www.apple.com/legal/privacy</a>#', $html, "Links with target=_blank"); |
| | | $this->assertRegExp('#\\[<a href="http://example.com/\\?tx\\[a\\]=5" target="_blank">http://example.com/\\?tx\\[a\\]=5</a>\\]#', $html, "Links with square brackets"); |
| | | $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"); |
| | | $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"); |
| | | } |
| | | |
| | | /** |
| | |
| | | $html = rcmail_html4inline(rcmail_print_body($part, array('safe' => false)), 'foo'); |
| | | |
| | | $mailto = '<a href="mailto:me@me.com?subject=this is the subject&body=this is the body"' |
| | | .' onclick="return rcmail.command(\'compose\',\'me@me.com?subject=this is the subject&body=this is the body\',this)">e-mail</a>'; |
| | | .' onclick="return rcmail.command(\'compose\',\'me@me.com?subject=this is the subject&body=this is the body\',this)" rel="noreferrer">e-mail</a>'; |
| | | |
| | | $this->assertRegExp('|'.preg_quote($mailto, '|').'|', $html, "Extended mailto links"); |
| | | } |