mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #2853 from hafriedlander/feature/htmltext_whitelist
NEW Allow specifying element whitelist in HTMLText fields
This commit is contained in:
commit
9b57609fcd
13
docs/en/changelogs/rc/3.1.3-rc1.md
Normal file
13
docs/en/changelogs/rc/3.1.3-rc1.md
Normal file
@ -0,0 +1,13 @@
|
||||
# 3.1.3-rc1
|
||||
|
||||
## Overview
|
||||
|
||||
* ExtraMeta fields can now only contain `meta` and `link` elements
|
||||
|
||||
## Upgrading
|
||||
|
||||
### ExtraMeta fields can now only contain `meta` and `link` elements
|
||||
|
||||
Previously ExtraMeta fields could contain any HTML elements. From 3.1.3-rc1 the contents are filtered
|
||||
on write to only allow `meta` and `link` elements. The first time after upgrading that you save a page
|
||||
that has other elements in ExtraMeta they will be deleted.
|
@ -34,12 +34,45 @@ class HTMLText extends Text {
|
||||
|
||||
protected $processShortcodes = true;
|
||||
|
||||
protected $whitelist = false;
|
||||
|
||||
public function __construct($name = null, $options = array()) {
|
||||
if(is_string($options)) {
|
||||
$options = array('whitelist' => $options);
|
||||
}
|
||||
|
||||
return parent::__construct($name, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* Options accepted in addition to those provided by Text:
|
||||
*
|
||||
* - shortcodes: If true, shortcodes will be turned into the appropriate HTML.
|
||||
* If false, shortcodes will not be processed.
|
||||
*
|
||||
* - whitelist: If provided, a comma-separated list of elements that will be allowed to be stored
|
||||
* (be careful on relying on this for XSS protection - some seemingly-safe elements allow
|
||||
* attributes that can be exploited, for instance <img onload="exploiting_code();" src="..." />)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setOptions(array $options = array()) {
|
||||
parent::setOptions($options);
|
||||
|
||||
if(array_key_exists("shortcodes", $options)) {
|
||||
$this->processShortcodes = !!$options["shortcodes"];
|
||||
}
|
||||
|
||||
if(array_key_exists("whitelist", $options)) {
|
||||
if(is_array($options['whitelist'])) {
|
||||
$this->whitelist = $options['whitelist'];
|
||||
}
|
||||
else {
|
||||
$this->whitelist = preg_split('/,\s*/', $options['whitelist']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,7 +182,24 @@ class HTMLText extends Text {
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function prepValueForDB($value) {
|
||||
if($this->whitelist) {
|
||||
$dom = Injector::inst()->create('HTMLValue', $value);
|
||||
|
||||
$query = array();
|
||||
foreach ($this->whitelist as $tag) $query[] = 'not(self::'.$tag.')';
|
||||
|
||||
foreach($dom->query('//body//*['.implode(' and ', $query).']') as $el) {
|
||||
if ($el->parentNode) $el->parentNode->removeChild($el);
|
||||
}
|
||||
|
||||
$value = $dom->getContent();
|
||||
}
|
||||
|
||||
return parent::prepValueForDB($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the field has meaningful content.
|
||||
* Excludes null content like <h1></h1>, <p></p> ,etc
|
||||
|
@ -176,4 +176,14 @@ class HTMLTextTest extends SapphireTest {
|
||||
$h->setValue("<p>test</p>");
|
||||
$this->assertTrue($h->exists());
|
||||
}
|
||||
|
||||
function testWhitelist() {
|
||||
$textObj = new HTMLText('Test', 'meta,link');
|
||||
|
||||
$this->assertEquals(
|
||||
$textObj->prepValueForDB('<meta content="Keep"><link href="Also Keep">'),
|
||||
$textObj->prepValueForDB('<meta content="Keep"><p>Remove</p><link href="Also Keep" />'),
|
||||
'Removes any elements not in whitelist'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user