mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2024-11-09 23:28:42 +00:00
Add HTML.Noopener to add a noopener rel to every external link
This has performance benefits https://jakearchibald.com/2016/performance-benefits-of-rel-noopener/ but most importantly also security benefits https://mathiasbynens.github.io/rel-noopener/ Adresses https://github.com/ezyang/htmlpurifier/issues/96
This commit is contained in:
parent
d4a96463ef
commit
c82051c3e1
1
NEWS
1
NEWS
@ -19,6 +19,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
|
|||||||
- Deleted some asserts to avoid linters from choking (#97)
|
- Deleted some asserts to avoid linters from choking (#97)
|
||||||
- Rework Serializer cache behavior to avoid chmod'ing if possible (#32)
|
- Rework Serializer cache behavior to avoid chmod'ing if possible (#32)
|
||||||
- Embedded semicolons in strings in CSS are now handled correctly!
|
- Embedded semicolons in strings in CSS are now handled correctly!
|
||||||
|
! Added %HTML.Noopener to add rel="noopener" to external links.
|
||||||
|
|
||||||
4.8.0, released 2016-07-16
|
4.8.0, released 2016-07-16
|
||||||
# By default, when a link has a target attribute associated
|
# By default, when a link has a target attribute associated
|
||||||
|
@ -222,14 +222,19 @@
|
|||||||
<line>268</line>
|
<line>268</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="HTML.TargetBlank">
|
<directive id="HTML.Noopener">
|
||||||
<file name="HTMLPurifier/HTMLModuleManager.php">
|
<file name="HTMLPurifier/HTMLModuleManager.php">
|
||||||
<line>271</line>
|
<line>271</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
|
<directive id="HTML.TargetBlank">
|
||||||
|
<file name="HTMLPurifier/HTMLModuleManager.php">
|
||||||
|
<line>274</line>
|
||||||
|
</file>
|
||||||
|
</directive>
|
||||||
<directive id="HTML.TargetNoreferrer">
|
<directive id="HTML.TargetNoreferrer">
|
||||||
<file name="HTMLPurifier/HTMLModuleManager.php">
|
<file name="HTMLPurifier/HTMLModuleManager.php">
|
||||||
<line>276</line>
|
<line>279</line>
|
||||||
</file>
|
</file>
|
||||||
</directive>
|
</directive>
|
||||||
<directive id="Attr.IDBlacklist">
|
<directive id="Attr.IDBlacklist">
|
||||||
|
@ -132,6 +132,7 @@ require 'HTMLPurifier/AttrTransform/Length.php';
|
|||||||
require 'HTMLPurifier/AttrTransform/Name.php';
|
require 'HTMLPurifier/AttrTransform/Name.php';
|
||||||
require 'HTMLPurifier/AttrTransform/NameSync.php';
|
require 'HTMLPurifier/AttrTransform/NameSync.php';
|
||||||
require 'HTMLPurifier/AttrTransform/Nofollow.php';
|
require 'HTMLPurifier/AttrTransform/Nofollow.php';
|
||||||
|
require 'HTMLPurifier/AttrTransform/Noopener.php';
|
||||||
require 'HTMLPurifier/AttrTransform/SafeEmbed.php';
|
require 'HTMLPurifier/AttrTransform/SafeEmbed.php';
|
||||||
require 'HTMLPurifier/AttrTransform/SafeObject.php';
|
require 'HTMLPurifier/AttrTransform/SafeObject.php';
|
||||||
require 'HTMLPurifier/AttrTransform/SafeParam.php';
|
require 'HTMLPurifier/AttrTransform/SafeParam.php';
|
||||||
@ -163,6 +164,7 @@ require 'HTMLPurifier/HTMLModule/Legacy.php';
|
|||||||
require 'HTMLPurifier/HTMLModule/List.php';
|
require 'HTMLPurifier/HTMLModule/List.php';
|
||||||
require 'HTMLPurifier/HTMLModule/Name.php';
|
require 'HTMLPurifier/HTMLModule/Name.php';
|
||||||
require 'HTMLPurifier/HTMLModule/Nofollow.php';
|
require 'HTMLPurifier/HTMLModule/Nofollow.php';
|
||||||
|
require 'HTMLPurifier/HTMLModule/Noopener.php';
|
||||||
require 'HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
|
require 'HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
|
||||||
require 'HTMLPurifier/HTMLModule/Object.php';
|
require 'HTMLPurifier/HTMLModule/Object.php';
|
||||||
require 'HTMLPurifier/HTMLModule/Presentation.php';
|
require 'HTMLPurifier/HTMLModule/Presentation.php';
|
||||||
|
@ -126,6 +126,7 @@ require_once $__dir . '/HTMLPurifier/AttrTransform/Length.php';
|
|||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/NameSync.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/NameSync.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/Nofollow.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/Nofollow.php';
|
||||||
|
require_once $__dir . '/HTMLPurifier/AttrTransform/Noopener.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeEmbed.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeEmbed.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php';
|
||||||
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
|
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
|
||||||
@ -157,6 +158,7 @@ require_once $__dir . '/HTMLPurifier/HTMLModule/Legacy.php';
|
|||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/List.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/List.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/Name.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Name.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/Nofollow.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Nofollow.php';
|
||||||
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Noopener.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/Object.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Object.php';
|
||||||
require_once $__dir . '/HTMLPurifier/HTMLModule/Presentation.php';
|
require_once $__dir . '/HTMLPurifier/HTMLModule/Presentation.php';
|
||||||
|
52
library/HTMLPurifier/AttrTransform/Noopener.php
Normal file
52
library/HTMLPurifier/AttrTransform/Noopener.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// must be called POST validation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds rel="noopener" to all outbound links. This transform is
|
||||||
|
* only attached if Attr.Noopener is TRUE.
|
||||||
|
*/
|
||||||
|
class HTMLPurifier_AttrTransform_Noopener extends HTMLPurifier_AttrTransform
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @type HTMLPurifier_URIParser
|
||||||
|
*/
|
||||||
|
private $parser;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->parser = new HTMLPurifier_URIParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $attr
|
||||||
|
* @param HTMLPurifier_Config $config
|
||||||
|
* @param HTMLPurifier_Context $context
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function transform($attr, $config, $context)
|
||||||
|
{
|
||||||
|
if (!isset($attr['href'])) {
|
||||||
|
return $attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX Kind of inefficient
|
||||||
|
$url = $this->parser->parse($attr['href']);
|
||||||
|
$scheme = $url->getSchemeObj($config, $context);
|
||||||
|
|
||||||
|
if ($scheme->browsable && !$url->isLocal($config, $context)) {
|
||||||
|
if (isset($attr['rel'])) {
|
||||||
|
$rels = explode(' ', $attr['rel']);
|
||||||
|
if (!in_array('noopener', $rels)) {
|
||||||
|
$rels[] = 'noopener';
|
||||||
|
}
|
||||||
|
$attr['rel'] = implode(' ', $rels);
|
||||||
|
} else {
|
||||||
|
$attr['rel'] = 'noopener';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $attr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: et sw=4 sts=4
|
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
HTML.Noopener
|
||||||
|
TYPE: bool
|
||||||
|
VERSION: 4.9.0
|
||||||
|
DEFAULT: FALSE
|
||||||
|
--DESCRIPTION--
|
||||||
|
If enabled, noopener rel attributes are added to all outgoing links.
|
||||||
|
--# vim: et sw=4 sts=4
|
25
library/HTMLPurifier/HTMLModule/Noopener.php
Normal file
25
library/HTMLPurifier/HTMLModule/Noopener.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module adds the noopener attribute transformation to a tags. It
|
||||||
|
* is enabled by HTML.Noopener
|
||||||
|
*/
|
||||||
|
class HTMLPurifier_HTMLModule_Noopener extends HTMLPurifier_HTMLModule
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
public $name = 'Noopener';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param HTMLPurifier_Config $config
|
||||||
|
*/
|
||||||
|
public function setup($config)
|
||||||
|
{
|
||||||
|
$a = $this->addBlankElement('a');
|
||||||
|
$a->attr_transform_post[] = new HTMLPurifier_AttrTransform_Noopener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: et sw=4 sts=4
|
@ -268,6 +268,9 @@ class HTMLPurifier_HTMLModuleManager
|
|||||||
if ($config->get('HTML.Nofollow')) {
|
if ($config->get('HTML.Nofollow')) {
|
||||||
$modules[] = 'Nofollow';
|
$modules[] = 'Nofollow';
|
||||||
}
|
}
|
||||||
|
if ($config->get('HTML.Noopener')) {
|
||||||
|
$modules[] = 'Noopener';
|
||||||
|
}
|
||||||
if ($config->get('HTML.TargetBlank')) {
|
if ($config->get('HTML.TargetBlank')) {
|
||||||
$modules[] = 'TargetBlank';
|
$modules[] = 'TargetBlank';
|
||||||
}
|
}
|
||||||
|
30
tests/HTMLPurifier/HTMLModule/NoopenerTest.php
Normal file
30
tests/HTMLPurifier/HTMLModule/NoopenerTest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class HTMLPurifier_HTMLModule_NoopenerTest extends HTMLPurifier_HTMLModuleHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->config->set('HTML.Noopener', true);
|
||||||
|
$this->config->set('Attr.AllowedRel', array("noopener", "blah"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNoopener()
|
||||||
|
{
|
||||||
|
$this->assertResult(
|
||||||
|
'<a href="http://google.com">x</a><a href="http://google.com" rel="blah">a</a><a href="/local">b</a><a href="mailto:foo@example.com">c</a>',
|
||||||
|
'<a href="http://google.com" rel="noopener">x</a><a href="http://google.com" rel="blah noopener">a</a><a href="/local">b</a><a href="mailto:foo@example.com">c</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNoopenerDupe()
|
||||||
|
{
|
||||||
|
$this->assertResult(
|
||||||
|
'<a href="http://google.com" rel="noopener">x</a><a href="http://google.com" rel="blah noopener">a</a><a href="/local">b</a><a href="mailto:foo@example.com">c</a>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: et sw=4 sts=4
|
Loading…
Reference in New Issue
Block a user