From e0354fecd9f58b53136bb9f9bfb8ff54a4ec1f8e Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Fri, 30 Dec 2011 22:56:44 +0800 Subject: [PATCH] Make forms work for transitional doctypes. Signed-off-by: Edward Z. Yang --- NEWS | 1 + library/HTMLPurifier.includes.php | 1 + library/HTMLPurifier.safe-includes.php | 1 + library/HTMLPurifier/AttrDef/Clone.php | 28 ++++++++++++++++++++++++++++ library/HTMLPurifier/AttrTypes.php | 14 ++++++++++++++ library/HTMLPurifier/HTMLModule/Forms.php | 3 ++- library/HTMLPurifier/HTMLModule/Legacy.php | 18 +++++++++++++++++- library/HTMLPurifier/HTMLModuleManager.php | 7 +++++++ tests/HTMLPurifier/HTMLModule/FormsTest.php | 19 ++++++++++++++++++- 9 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 library/HTMLPurifier/AttrDef/Clone.php diff --git a/NEWS b/NEWS index 531905d0..df347552 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier ! Implement iframes, and allow them to be used in untrusted mode with %HTML.SafeIframe and %URI.SafeIframeRegexp. Thanks Bradley M. Froehle for submitting an initial version of the patch. +! The Forms module now works properly for transitional doctypes. - Color keywords are now case insensitive. Thanks Yzmir Ramirez for reporting. - Explicitly initialize anonModule variable to null. diff --git a/library/HTMLPurifier.includes.php b/library/HTMLPurifier.includes.php index ad9b604e..47eba544 100644 --- a/library/HTMLPurifier.includes.php +++ b/library/HTMLPurifier.includes.php @@ -73,6 +73,7 @@ require 'HTMLPurifier/UnitConverter.php'; require 'HTMLPurifier/VarParser.php'; require 'HTMLPurifier/VarParserException.php'; require 'HTMLPurifier/AttrDef/CSS.php'; +require 'HTMLPurifier/AttrDef/Clone.php'; require 'HTMLPurifier/AttrDef/Enum.php'; require 'HTMLPurifier/AttrDef/Integer.php'; require 'HTMLPurifier/AttrDef/Lang.php'; diff --git a/library/HTMLPurifier.safe-includes.php b/library/HTMLPurifier.safe-includes.php index 75d9fd85..3902b878 100644 --- a/library/HTMLPurifier.safe-includes.php +++ b/library/HTMLPurifier.safe-includes.php @@ -67,6 +67,7 @@ require_once $__dir . '/HTMLPurifier/UnitConverter.php'; require_once $__dir . '/HTMLPurifier/VarParser.php'; require_once $__dir . '/HTMLPurifier/VarParserException.php'; require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php'; +require_once $__dir . '/HTMLPurifier/AttrDef/Clone.php'; require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php'; require_once $__dir . '/HTMLPurifier/AttrDef/Integer.php'; require_once $__dir . '/HTMLPurifier/AttrDef/Lang.php'; diff --git a/library/HTMLPurifier/AttrDef/Clone.php b/library/HTMLPurifier/AttrDef/Clone.php new file mode 100644 index 00000000..ce68dbd5 --- /dev/null +++ b/library/HTMLPurifier/AttrDef/Clone.php @@ -0,0 +1,28 @@ +clone = $clone; + } + + public function validate($v, $config, $context) { + return $this->clone->validate($v, $config, $context); + } + + public function make($string) { + return clone $this->clone; + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/AttrTypes.php b/library/HTMLPurifier/AttrTypes.php index fc2ea4e5..6f985ff9 100644 --- a/library/HTMLPurifier/AttrTypes.php +++ b/library/HTMLPurifier/AttrTypes.php @@ -15,6 +15,13 @@ class HTMLPurifier_AttrTypes * types. */ public function __construct() { + // XXX This is kind of poor, since we don't actually /clone/ + // instances; instead, we use the supplied make() attribute. So, + // the underlying class must know how to deal with arguments. + // With the old implementation of Enum, that ignored its + // arguments when handling a make dispatch, the IAlign + // definition wouldn't work. + // pseudo-types, must be instantiated via shorthand $this->info['Enum'] = new HTMLPurifier_AttrDef_Enum(); $this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool(); @@ -29,6 +36,9 @@ class HTMLPurifier_AttrTypes $this->info['URI'] = new HTMLPurifier_AttrDef_URI(); $this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang(); $this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color(); + $this->info['IAlign'] = self::makeEnum('top,middle,bottom,left,right'); + $this->info['LAlign'] = self::makeEnum('top,bottom,left,right'); + $this->info['FrameTarget'] = new HTMLPurifier_AttrDef_HTML_FrameTarget(); // unimplemented aliases $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); @@ -44,6 +54,10 @@ class HTMLPurifier_AttrTypes $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); } + private static function makeEnum($in) { + return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in))); + } + /** * Retrieves a type * @param $type String type name diff --git a/library/HTMLPurifier/HTMLModule/Forms.php b/library/HTMLPurifier/HTMLModule/Forms.php index 139df2d7..b963529a 100644 --- a/library/HTMLPurifier/HTMLModule/Forms.php +++ b/library/HTMLPurifier/HTMLModule/Forms.php @@ -84,7 +84,8 @@ class HTMLPurifier_HTMLModule_Forms extends HTMLPurifier_HTMLModule $button->excludes = $this->makeLookup( 'form', 'fieldset', // Form 'input', 'select', 'textarea', 'label', 'button', // Formctrl - 'a' // as per HTML 4.01 spec, this is omitted by modularization + 'a', // as per HTML 4.01 spec, this is omitted by modularization + 'isindex', 'iframe' // legacy items ); // Extra exclusion: img usemap="" is not permitted within this element. diff --git a/library/HTMLPurifier/HTMLModule/Legacy.php b/library/HTMLPurifier/HTMLModule/Legacy.php index df33927b..f278eece 100644 --- a/library/HTMLPurifier/HTMLModule/Legacy.php +++ b/library/HTMLPurifier/HTMLModule/Legacy.php @@ -89,7 +89,7 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule $hr->attr['width'] = 'Length'; $img = $this->addBlankElement('img'); - $img->attr['align'] = 'Enum#top,middle,bottom,left,right'; + $img->attr['align'] = 'IAlign'; $img->attr['border'] = 'Pixels'; $img->attr['hspace'] = 'Pixels'; $img->attr['vspace'] = 'Pixels'; @@ -136,6 +136,22 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule $ul->attr['compact'] = 'Bool#compact'; $ul->attr['type'] = 'Enum#square,disc,circle'; + // "safe" modifications to "unsafe" elements + // WARNING: If you want to add support for an unsafe, legacy + // attribute, make a new TrustedLegacy module with the trusted + // bit set appropriately + + $form = $this->addBlankElement('form'); + $form->content_model = 'Flow | #PCDATA'; + $form->content_model_type = 'optional'; + $form->attr['target'] = 'FrameTarget'; + + $input = $this->addBlankElement('input'); + $input->attr['align'] = 'IAlign'; + + $legend = $this->addBlankElement('legend'); + $legend->attr['align'] = 'LAlign'; + } } diff --git a/library/HTMLPurifier/HTMLModuleManager.php b/library/HTMLPurifier/HTMLModuleManager.php index 468cf46f..7a06fc02 100644 --- a/library/HTMLPurifier/HTMLModuleManager.php +++ b/library/HTMLPurifier/HTMLModuleManager.php @@ -369,6 +369,13 @@ class HTMLPurifier_HTMLModuleManager // :TODO: // non-standalone definitions that don't have a standalone // to merge into could be deferred to the end + // HOWEVER, it is perfectly valid for a non-standalone + // definition to lack a standalone definition, even + // after all processing: this allows us to safely + // specify extra attributes for elements that may not be + // enabled all in one place. In particular, this might + // be the case for trusted elements. WARNING: care must + // be taken that the /extra/ definitions are all safe. continue; } diff --git a/tests/HTMLPurifier/HTMLModule/FormsTest.php b/tests/HTMLPurifier/HTMLModule/FormsTest.php index 9d89cd8c..5bc4c99c 100644 --- a/tests/HTMLPurifier/HTMLModule/FormsTest.php +++ b/tests/HTMLPurifier/HTMLModule/FormsTest.php @@ -7,10 +7,10 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness parent::setUp(); $this->config->set('HTML.Trusted', true); $this->config->set('Attr.EnableID', true); - $this->config->set('Cache.DefinitionImpl', null); } function testBasicUse() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); $this->assertResult( // need support for label for later '
@@ -30,6 +30,7 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness } function testSelectOption() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); $this->assertResult('

@@ -49,6 +50,7 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness } function testSelectOptgroup() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); $this->assertResult('

@@ -74,6 +76,7 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness } function testTextarea() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); $this->assertResult('

@@ -90,6 +93,7 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness // label tests omitted function testFieldset() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); $this->assertResult('

@@ -122,17 +126,30 @@ class HTMLPurifier_HTMLModule_FormsTest extends HTMLPurifier_HTMLModuleHarness } function testInputTransform() { + $this->config->set('HTML.Doctype', 'XHTML 1.0 Strict'); $this->assertResult('', ''); } function testTextareaTransform() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); $this->assertResult('', ''); } function testTextInFieldset() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); $this->assertResult('
foo
'); } + function testStrict() { + $this->config->set('HTML.Doctype', 'HTML 4.01 Strict'); + $this->assertResult('', ''); + } + + function testLegacy() { + $this->assertResult('
'); + $this->assertResult('
'); + } + } // vim: et sw=4 sts=4 -- 2.11.4.GIT