mirror of
https://github.com/silverstripe/silverstripe-comments
synced 2024-10-22 11:05:49 +02:00
NEW Optionally allow (sanitized) HTML in comments
This commit is contained in:
parent
83a6de252f
commit
e450807b1c
@ -31,7 +31,9 @@ class Commenting {
|
||||
'comments_per_page' => 10,
|
||||
'comments_holder_id' => "comments-holder", // id for the comments holder
|
||||
'comment_permalink_prefix' => "comment-", // id prefix for each comment. If needed make this different
|
||||
'require_moderation' => false
|
||||
'require_moderation' => false,
|
||||
'html_allowed' => false, // allow for sanitized HTML in comments
|
||||
'html_allowed_elements' => array('p', 'br', 'a', 'img', 'i', 'b')
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@ class Comment extends DataObject {
|
||||
|
||||
public static $db = array(
|
||||
"Name" => "Varchar(200)",
|
||||
"Comment" => "Text",
|
||||
"Comment" => "Text", // can contain sanitized HTML with 'html_allowed=true' config
|
||||
"Email" => "Varchar(200)",
|
||||
"URL" => "Varchar(255)",
|
||||
"BaseClass" => "Varchar(200)",
|
||||
@ -55,7 +55,14 @@ class Comment extends DataObject {
|
||||
'IsSpam' => 'Is Spam'
|
||||
);
|
||||
|
||||
public function onBeforeWrite() {
|
||||
parent::onBeforeWrite();
|
||||
|
||||
// Sanitize HTML, because its expected to be passed to the template unescaped later
|
||||
if($this->getAllowHtml()) {
|
||||
$this->Comment = $this->purifyHtml($this->Comment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates the old {@link PageComment} objects to {@link Comment}
|
||||
@ -330,4 +337,34 @@ class Comment extends DataObject {
|
||||
$fields->replaceField('BaseClass', $baseClassField);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function getAllowHtml() {
|
||||
return (
|
||||
Commenting::has_commenting($this->BaseClass)
|
||||
&& Commenting::get_config_value($this->BaseClass, 'html_allowed')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $dirtyHtml
|
||||
* @return String
|
||||
*/
|
||||
public function purifyHtml($dirtyHtml) {
|
||||
$purifier = $this->getHtmlPurifierService();
|
||||
return $purifier->purify($dirtyHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HTMLPurifier (or anything with a "purify()" method)
|
||||
*/
|
||||
public function getHtmlPurifierService() {
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$config->set('HTML.AllowedElements',
|
||||
Commenting::get_config_value($this->BaseClass, 'html_allowed_elements')
|
||||
);
|
||||
$config->set('AutoFormat.AutoParagraph', true);
|
||||
$config->set('AutoFormat.Linkify', true);
|
||||
$config->set('URI.DisableExternalResources', true);
|
||||
return new HTMLPurifier($config);
|
||||
}
|
||||
}
|
||||
|
@ -12,5 +12,8 @@
|
||||
"require":
|
||||
{
|
||||
"silverstripe/framework": "3.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ezyang/htmlpurifier": "4.*"
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
## Configuration
|
||||
# Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
The module provides a number of built in configuration settings below are the default settings
|
||||
|
||||
@ -13,7 +15,9 @@ The module provides a number of built in configuration settings below are the de
|
||||
'comments_per_page' => 10,
|
||||
'comments_holder_id' => "comments-holder",
|
||||
'comment_permalink_prefix' => "comment-",
|
||||
'require_moderation' => false
|
||||
'require_moderation' => false,
|
||||
'html_allowed' => false, // allow for sanitized HTML in comments
|
||||
'html_allowed_elements' => array('p', 'br', 'a', 'img', 'i', 'b')
|
||||
);
|
||||
|
||||
If you want to customize any of the configuration options after you have added the extension (or
|
||||
@ -25,4 +29,21 @@ on the built-in SiteTree commenting) use `set_config_value`
|
||||
// mysite/_config.php - Returns the setting
|
||||
Commenting::get_config_value('SiteTree', 'require_login');
|
||||
|
||||
## HTML Comments
|
||||
|
||||
Comments can be configured to contain a restricted set of HTML tags
|
||||
through the `html_allowed` and `html_allowed_elements` settings.
|
||||
Raw HTML is hardly user friendly, but combined with a rich-text editor
|
||||
of your own choosing it can allow rich comment formatting.
|
||||
|
||||
In order to use this feature, you need to install the
|
||||
[HTMLPurifier](http://htmlpurifier.org/) library.
|
||||
The easiest way to do this is through [Composer](http://getcomposer.org).
|
||||
|
||||
{
|
||||
"require": {"ezyang/htmlpurifier": "4.*"}
|
||||
}
|
||||
|
||||
**Important**: Rendering user-provided HTML on your website always risks
|
||||
exposing your users to cross-site scripting (XSS) attacks, if the HTML
|
||||
isn't properly sanitized. Don't allow tags like `<script>` or arbitrary attributes.
|
||||
|
@ -1,5 +1,9 @@
|
||||
<div class="comment" id="$Permalink">
|
||||
<% if AllowHtml %>
|
||||
$Comment.RAW
|
||||
<% else %>
|
||||
<p>$Comment.XML</p>
|
||||
<% end_if %>
|
||||
</div>
|
||||
|
||||
<p class="info">
|
||||
|
@ -155,6 +155,73 @@ class CommentsTest extends FunctionalTest {
|
||||
$this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol');
|
||||
}
|
||||
}
|
||||
|
||||
public function testSanitizesWithAllowHtml() {
|
||||
if(!class_exists('HTMLPurifier')) {
|
||||
$this->markTestSkipped('HTMLPurifier class not found');
|
||||
return;
|
||||
}
|
||||
|
||||
$origAllowed = Commenting::get_config_value('CommentableItem','html_allowed');
|
||||
|
||||
// Without HTML allowed
|
||||
$comment1 = new Comment();
|
||||
$comment1->BaseClass = 'CommentableItem';
|
||||
$comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>';
|
||||
$comment1->write();
|
||||
$this->assertEquals(
|
||||
'<p><script>alert("w00t")</script>my comment</p>',
|
||||
$comment1->Comment,
|
||||
'Does not remove HTML tags with html_allowed=false, ' .
|
||||
'which is correct behaviour because the HTML will be escaped'
|
||||
);
|
||||
|
||||
// With HTML allowed
|
||||
Commenting::set_config_value('CommentableItem','html_allowed', true);
|
||||
$comment2 = new Comment();
|
||||
$comment2->BaseClass = 'CommentableItem';
|
||||
$comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>';
|
||||
$comment2->write();
|
||||
$this->assertEquals(
|
||||
'<p>my comment</p>',
|
||||
$comment2->Comment,
|
||||
'Removes HTML tags which are not on the whitelist'
|
||||
);
|
||||
|
||||
Commenting::set_config_value('CommentableItem','html_allowed', $origAllowed);
|
||||
}
|
||||
|
||||
public function testDefaultTemplateRendersHtmlWithAllowHtml() {
|
||||
if(!class_exists('HTMLPurifier')) {
|
||||
$this->markTestSkipped('HTMLPurifier class not found');
|
||||
}
|
||||
|
||||
$origAllowed = Commenting::get_config_value('CommentableItem', 'html_allowed');
|
||||
$item = new CommentableItem();
|
||||
$item->write();
|
||||
|
||||
// Without HTML allowed
|
||||
$comment = new Comment();
|
||||
$comment->Comment = '<p>my comment</p>';
|
||||
$comment->ParentID = $item->ID;
|
||||
$comment->BaseClass = 'CommentableItem';
|
||||
$comment->write();
|
||||
|
||||
$html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
|
||||
$this->assertContains(
|
||||
'<p>my comment</p>',
|
||||
$html
|
||||
);
|
||||
|
||||
Commenting::set_config_value('CommentableItem','html_allowed', true);
|
||||
$html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
|
||||
$this->assertContains(
|
||||
'<p>my comment</p>',
|
||||
$html
|
||||
);
|
||||
|
||||
Commenting::set_config_value('CommentableItem','html_allowed', $origAllowed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user