diff --git a/NEWS b/NEWS index ffa8f52e..225e65ca 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,10 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier - DefinitionCache no longer throws errors when it encounters old serial files that do not conform to the current style - Stray xmlns attributes removed from configuration documentation +- configForm.php smoketest no longer has XSS vulnerability due to + unescaped print_r output +- Printer adheres to configuration's directives on output format +- Fix improperly named form field in ConfigForm printer . Rewire some test-cases to swallow errors rather than expect them . HTMLDefinition printer updated with some of the new attributes . DefinitionCache keys reordered to reflect precedence: version number, @@ -36,6 +40,13 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier . Directives now keep track of aliases to themselves . Error collector now requires a severity to be passed, use PHP's internal error constants for this +. HTMLPurifier_Config::getAllowedDirectivesForForm implemented, allows + much easier selective embedding of configuration values +. Doctype objects now accept public and system DTD identifiers +. %HTML.Doctype is now constrained by specific values, to specify a custom + doctype use new %HTML.CustomDoctype +. ConfigForm truncates long directives to keep the form small, and does + not re-output namespaces 2.0.0, released 2007-06-20 # Completely refactored HTMLModuleManager, decentralizing safety diff --git a/library/HTMLPurifier/Config.php b/library/HTMLPurifier/Config.php index 14da7dcd..d9b34c1e 100644 --- a/library/HTMLPurifier/Config.php +++ b/library/HTMLPurifier/Config.php @@ -341,25 +341,78 @@ class HTMLPurifier_Config } } + /** + * Returns a list of array(namespace, directive) for all directives + * that are allowed in a web-form context as per an allowed + * namespaces/directives list. + * @param $allowed List of allowed namespaces/directives + * @static + */ + function getAllowedDirectivesForForm($allowed) { + $schema = HTMLPurifier_ConfigSchema::instance(); + if ($allowed !== true) { + if (is_string($allowed)) $allowed = array($allowed); + $allowed_ns = array(); + $allowed_directives = array(); + $blacklisted_directives = array(); + foreach ($allowed as $ns_or_directive) { + if (strpos($ns_or_directive, '.') !== false) { + // directive + if ($ns_or_directive[0] == '-') { + $blacklisted_directives[substr($ns_or_directive, 1)] = true; + } else { + $allowed_directives[$ns_or_directive] = true; + } + } else { + // namespace + $allowed_ns[$ns_or_directive] = true; + } + } + } + $ret = array(); + foreach ($schema->info as $ns => $keypairs) { + foreach ($keypairs as $directive => $def) { + if ($allowed !== true) { + if (isset($blacklisted_directives["$ns.$directive"])) continue; + if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue; + } + if ($def->class == 'alias') continue; + if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue; + $ret[] = array($ns, $directive); + } + } + return $ret; + } + /** * Loads configuration values from $_GET/$_POST that were posted * via ConfigForm * @param $array $_GET or $_POST array to import * @param $index Index/name that the config variables are in + * @param $allowed List of allowed namespaces/directives * @param $mq_fix Boolean whether or not to enable magic quotes fix * @static */ - function loadArrayFromForm($array, $index, $mq_fix = true) { + function loadArrayFromForm($array, $index, $allowed = true, $mq_fix = true) { $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); $mq = get_magic_quotes_gpc() && $mq_fix; - foreach ($array as $key => $value) { - if (!strncmp($key, 'Null_', 5) && !empty($value)) { - unset($array[substr($key, 5)]); - unset($array[$key]); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed); + $ret = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $skey = "$ns.$directive"; + if (!empty($array["Null_$skey"])) { + $ret[$ns][$directive] = null; + continue; } - if ($mq) $array[$key] = stripslashes($value); + if (!isset($array[$skey])) continue; + $value = $mq ? stripslashes($array[$skey]) : $array[$skey]; + $ret[$ns][$directive] = $value; } - return @HTMLPurifier_Config::create($array); + + $config = HTMLPurifier_Config::create($ret); + return $config; } /** diff --git a/library/HTMLPurifier/Doctype.php b/library/HTMLPurifier/Doctype.php index d6e2c4ab..8fee70c4 100644 --- a/library/HTMLPurifier/Doctype.php +++ b/library/HTMLPurifier/Doctype.php @@ -34,23 +34,33 @@ class HTMLPurifier_Doctype */ var $aliases = array(); + /** + * Public DTD identifier + */ + var $dtdPublic; + + /** + * System DTD identifier + */ + var $dtdSystem; + function HTMLPurifier_Doctype($name = null, $xml = true, $modules = array(), - $tidyModules = array(), $aliases = array() + $tidyModules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null ) { $this->name = $name; $this->xml = $xml; $this->modules = $modules; $this->tidyModules = $tidyModules; $this->aliases = $aliases; + $this->dtdPublic = $dtd_public; + $this->dtdSystem = $dtd_system; } /** * Clones the doctype, use before resolving modes and the like */ function copy() { - return new HTMLPurifier_Doctype( - $this->name, $this->xml, $this->modules, $this->tidyModules, $this->aliases - ); + return unserialize(serialize($this)); } } diff --git a/library/HTMLPurifier/DoctypeRegistry.php b/library/HTMLPurifier/DoctypeRegistry.php index 57ccd506..52d0a706 100644 --- a/library/HTMLPurifier/DoctypeRegistry.php +++ b/library/HTMLPurifier/DoctypeRegistry.php @@ -44,14 +44,14 @@ class HTMLPurifier_DoctypeRegistry * @return Reference to registered doctype (usable for further editing) */ function ®ister($doctype, $xml = true, $modules = array(), - $tidy_modules = array(), $aliases = array() + $tidy_modules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null ) { if (!is_array($modules)) $modules = array($modules); if (!is_array($tidy_modules)) $tidy_modules = array($tidy_modules); if (!is_array($aliases)) $aliases = array($aliases); if (!is_object($doctype)) { $doctype = new HTMLPurifier_Doctype( - $doctype, $xml, $modules, $tidy_modules, $aliases + $doctype, $xml, $modules, $tidy_modules, $aliases, $dtd_public, $dtd_system ); } $this->doctypes[$doctype->name] =& $doctype; @@ -76,7 +76,7 @@ class HTMLPurifier_DoctypeRegistry function &get($doctype) { if (isset($this->aliases[$doctype])) $doctype = $this->aliases[$doctype]; if (!isset($this->doctypes[$doctype])) { - trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist'); + trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR); $anon = new HTMLPurifier_Doctype($doctype); return $anon; } @@ -103,9 +103,9 @@ class HTMLPurifier_DoctypeRegistry function getDoctypeFromConfig($config) { // recommended test $doctype = $config->get('HTML', 'Doctype'); - if ($doctype !== null) { - return $doctype; - } + if (!empty($doctype)) return $doctype; + $doctype = $config->get('HTML', 'CustomDoctype'); + if (!empty($doctype)) return $doctype; // backwards-compatibility if ($config->get('HTML', 'XHTML')) { $doctype = 'XHTML 1.0'; diff --git a/library/HTMLPurifier/HTMLModuleManager.php b/library/HTMLPurifier/HTMLModuleManager.php index c46a8b2c..8bc11592 100644 --- a/library/HTMLPurifier/HTMLModuleManager.php +++ b/library/HTMLPurifier/HTMLModuleManager.php @@ -37,14 +37,27 @@ require_once 'HTMLPurifier/HTMLModule/Tidy/XHTMLStrict.php'; require_once 'HTMLPurifier/HTMLModule/Tidy/Proprietary.php'; HTMLPurifier_ConfigSchema::define( - 'HTML', 'Doctype', null, 'string/null', - 'Doctype to use, pre-defined values are HTML 4.01 Transitional, HTML 4.01 '. - 'Strict, XHTML 1.0 Transitional, XHTML 1.0 Strict, XHTML 1.1. '. + 'HTML', 'Doctype', '', 'string', + 'Doctype to use during filtering. '. 'Technically speaking this is not actually a doctype (as it does '. 'not identify a corresponding DTD), but we are using this name '. - 'for sake of simplicity. This will override any older directives '. + 'for sake of simplicity. When non-blank, this will override any older directives '. 'like %HTML.XHTML or %HTML.Strict.' ); +HTMLPurifier_ConfigSchema::defineAllowedValues('HTML', 'Doctype', array( + '', 'HTML 4.01 Transitional', 'HTML 4.01 Strict', + 'XHTML 1.0 Transitional', 'XHTML 1.0 Strict', + 'XHTML 1.1' +)); + +HTMLPurifier_ConfigSchema::define( + 'HTML', 'CustomDoctype', null, 'string/null', +' +A custom doctype for power-users who defined there own document +type. This directive only applies when %HTML.Doctype is blank. +This directive has been available since 2.0.1. +' +); HTMLPurifier_ConfigSchema::define( 'HTML', 'Trusted', false, 'bool', @@ -167,31 +180,46 @@ class HTMLPurifier_HTMLModuleManager $this->doctypes->register( 'HTML 4.01 Transitional', false, array_merge($common, $transitional, $non_xml), - array('Tidy_Transitional', 'Tidy_Proprietary') + array('Tidy_Transitional', 'Tidy_Proprietary'), + array(), + '-//W3C//DTD HTML 4.01 Transitional//EN', + 'http://www.w3.org/TR/html4/loose.dtd' ); $this->doctypes->register( 'HTML 4.01 Strict', false, array_merge($common, $non_xml), - array('Tidy_Strict', 'Tidy_Proprietary') + array('Tidy_Strict', 'Tidy_Proprietary'), + array(), + '-//W3C//DTD HTML 4.01//EN', + 'http://www.w3.org/TR/html4/strict.dtd' ); $this->doctypes->register( 'XHTML 1.0 Transitional', true, array_merge($common, $transitional, $xml, $non_xml), - array('Tidy_Transitional', 'Tidy_XHTML', 'Tidy_Proprietary') + array('Tidy_Transitional', 'Tidy_XHTML', 'Tidy_Proprietary'), + array(), + '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' ); $this->doctypes->register( 'XHTML 1.0 Strict', true, array_merge($common, $xml, $non_xml), - array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_XHTMLStrict', 'Tidy_Proprietary') + array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_XHTMLStrict', 'Tidy_Proprietary'), + array(), + '-//W3C//DTD XHTML 1.0 Strict//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd' ); $this->doctypes->register( 'XHTML 1.1', true, array_merge($common, $xml), - array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary') // Tidy_XHTML1_1 + array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary'), // Tidy_XHTML1_1 + array(), + '-//W3C//DTD XHTML 1.1//EN', + 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd' ); } diff --git a/library/HTMLPurifier/Printer.php b/library/HTMLPurifier/Printer.php index 95be17a2..8fa23f5e 100644 --- a/library/HTMLPurifier/Printer.php +++ b/library/HTMLPurifier/Printer.php @@ -26,6 +26,16 @@ class HTMLPurifier_Printer $this->generator = new HTMLPurifier_Generator(); } + /** + * Give generator necessary configuration if possible + */ + function prepareGenerator($config) { + // hack for smoketests/configForm.php + if (empty($config->conf['HTML'])) return; + $context = new HTMLPurifier_Context(); + $this->generator->generateFromTokens(array(), $config, $context); + } + /** * Main function that renders object or aspect of that object * @note Parameters vary depending on printer diff --git a/library/HTMLPurifier/Printer/ConfigForm.php b/library/HTMLPurifier/Printer/ConfigForm.php index c157f2ab..c57f0bbe 100644 --- a/library/HTMLPurifier/Printer/ConfigForm.php +++ b/library/HTMLPurifier/Printer/ConfigForm.php @@ -38,18 +38,19 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer /** * Returns HTML output for a configuration form * @param $config Configuration object of current form state - * @param $ns Optional namespace(s) to restrict form to + * @param $allowed Optional namespace(s) and directives to restrict form to. */ - function render($config, $ns = true) { + function render($config, $allowed = true, $render_controls = true) { $this->config = $config; - if ($ns === true) { - $all = $config->getAll(); - } else { - if (is_string($ns)) $ns = array($ns); - foreach ($ns as $n) { - $all = array($n => $config->getBatch($n)); - } + $this->prepareGenerator($config); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed); + $all = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $all[$ns][$directive] = $config->get($ns, $directive); } + $ret = ''; $ret .= $this->start('table', array('class' => 'hp-config')); $ret .= $this->start('thead'); @@ -61,13 +62,16 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer foreach ($all as $ns => $directives) { $ret .= $this->renderNamespace($ns, $directives); } - $ret .= $this->start('tfoot'); - $ret .= $this->start('tr'); - $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); - $ret .= ' [Reset]'; - $ret .= $this->end('td'); - $ret .= $this->end('tr'); - $ret .= $this->end('tfoot'); + if ($render_controls) { + $ret .= $this->start('tfoot'); + $ret .= $this->start('tr'); + $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); + $ret .= $this->elementEmpty('input', array('type' => 'Submit', 'value' => 'Submit')); + $ret .= '[Reset]'; + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + $ret .= $this->end('tfoot'); + } $ret .= $this->end('table'); return $ret; } @@ -93,11 +97,20 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); $ret .= $this->start('a', array('href' => $url)); } + $attr = array('for' => "{$this->name}:$ns.$directive"); + // crop directive name if it's too long + if (strlen($directive) < 14) { + $directive_disp = $directive; + } else { + $directive_disp = substr($directive, 0, 12) . '...'; + $attr['title'] = $directive; + } + $ret .= $this->element( 'label', - "%$ns.$directive", + $directive_disp, // component printers must create an element with this id - array('for' => "{$this->name}:$ns.$directive") + $attr ); if ($this->docURL) $ret .= $this->end('a'); $ret .= $this->end('th'); @@ -136,6 +149,7 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer $this->obj = $obj; } function render($ns, $directive, $value, $name, $config) { + $this->prepareGenerator($config); $ret = ''; $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); @@ -145,7 +159,7 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer 'type' => 'checkbox', 'value' => '1', 'class' => 'null-toggle', - 'name' => "$name:Null_$ns.$directive", + 'name' => "$name"."[Null_$ns.$directive]", 'id' => "$name:Null_$ns.$directive", 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! ); @@ -163,6 +177,7 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer */ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { function render($ns, $directive, $value, $name, $config) { + $this->prepareGenerator($config); // this should probably be split up a little $ret = ''; $def = $config->def->info[$ns][$directive]; @@ -193,7 +208,6 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { $value = serialize($value); } $attr = array( - 'type' => 'text', 'name' => "$name"."[$ns.$directive]", 'id' => "$name:$ns.$directive" ); @@ -208,6 +222,7 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { $ret .= $this->end('select'); } else { $attr['value'] = $value; + $attr['type'] = 'text'; $ret .= $this->elementEmpty('input', $attr); } return $ret; @@ -219,8 +234,8 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { */ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer { function render($ns, $directive, $value, $name, $config) { + $this->prepareGenerator($config); $ret = ''; - $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); diff --git a/smoketests/printDefinition.php b/smoketests/printDefinition.php index 771d03bb..b82e79e0 100644 --- a/smoketests/printDefinition.php +++ b/smoketests/printDefinition.php @@ -6,7 +6,7 @@ require_once 'HTMLPurifier/Printer/HTMLDefinition.php'; require_once 'HTMLPurifier/Printer/CSSDefinition.php'; require_once 'HTMLPurifier/Printer/ConfigForm.php'; -$config = HTMLPurifier_Config::loadArrayFromForm($_GET, 'config'); +$config = HTMLPurifier_Config::loadArrayFromForm($_GET, 'config', 'HTML'); // you can do custom configuration! if (file_exists('printDefinition.settings.php')) { @@ -22,6 +22,7 @@ $printer_config_form = new HTMLPurifier_Printer_ConfigForm( ); echo ''; + ?> diff --git a/smoketests/testSchema.php b/smoketests/testSchema.php index 1295566e..f2e8e3bf 100644 --- a/smoketests/testSchema.php +++ b/smoketests/testSchema.php @@ -5,40 +5,36 @@ $custom_schema = new HTMLPurifier_ConfigSchema(); $old = HTMLPurifier_ConfigSchema::instance(); $custom_schema =& HTMLPurifier_ConfigSchema::instance($custom_schema); -if (!class_exists('CS')) { - class CS extends HTMLPurifier_ConfigSchema {} -} +HTMLPurifier_ConfigSchema::defineNamespace('Element', 'Chemical substances that cannot be further decomposed'); -CS::defineNamespace('Element', 'Chemical substances that cannot be further decomposed'); - -CS::define('Element', 'Abbr', 'H', 'string', 'Abbreviation of element name.'); -CS::define('Element', 'Name', 'hydrogen', 'istring', 'Full name of atoms.'); -CS::define('Element', 'Number', 1, 'int', 'Atomic number, is identity.'); -CS::define('Element', 'Mass', 1.00794, 'float', 'Atomic mass.'); -CS::define('Element', 'Radioactive', false, 'bool', 'Does it have rapid decay?'); -CS::define('Element', 'Isotopes', array('1' => true, '2' => true, '3' => true), 'lookup', +HTMLPurifier_ConfigSchema::define('Element', 'Abbr', 'H', 'string', 'Abbreviation of element name.'); +HTMLPurifier_ConfigSchema::define('Element', 'Name', 'hydrogen', 'istring', 'Full name of atoms.'); +HTMLPurifier_ConfigSchema::define('Element', 'Number', 1, 'int', 'Atomic number, is identity.'); +HTMLPurifier_ConfigSchema::define('Element', 'Mass', 1.00794, 'float', 'Atomic mass.'); +HTMLPurifier_ConfigSchema::define('Element', 'Radioactive', false, 'bool', 'Does it have rapid decay?'); +HTMLPurifier_ConfigSchema::define('Element', 'Isotopes', array('1' => true, '2' => true, '3' => true), 'lookup', 'What numbers of neutrons for this element have been observed?'); -CS::define('Element', 'Traits', array('nonmetallic', 'odorless', 'flammable'), 'list', +HTMLPurifier_ConfigSchema::define('Element', 'Traits', array('nonmetallic', 'odorless', 'flammable'), 'list', 'What are general properties of the element?'); -CS::define('Element', 'IsotopeNames', array('1' => 'protium', '2' => 'deuterium', '3' => 'tritium'), 'hash', +HTMLPurifier_ConfigSchema::define('Element', 'IsotopeNames', array('1' => 'protium', '2' => 'deuterium', '3' => 'tritium'), 'hash', 'Lookup hash of neutron counts to formal names.'); -CS::defineNamespace('Instrument', 'Of the musical type.'); +HTMLPurifier_ConfigSchema::defineNamespace('Instrument', 'Of the musical type.'); -CS::define('Instrument', 'Manufacturer', 'Yamaha', 'string', 'Who made it?'); -CS::defineAllowedValues('Instrument', 'Manufacturer', array( +HTMLPurifier_ConfigSchema::define('Instrument', 'Manufacturer', 'Yamaha', 'string', 'Who made it?'); +HTMLPurifier_ConfigSchema::defineAllowedValues('Instrument', 'Manufacturer', array( 'Yamaha', 'Conn-Selmer', 'Vandoren', 'Laubin', 'Buffet', 'other')); -CS::defineValueAliases('Instrument', 'Manufacturer', array( +HTMLPurifier_ConfigSchema::defineValueAliases('Instrument', 'Manufacturer', array( 'Selmer' => 'Conn-Selmer')); -CS::define('Instrument', 'Family', 'woodwind', 'istring', 'What family is it?'); -CS::defineAllowedValues('Instrument', 'Family', array( +HTMLPurifier_ConfigSchema::define('Instrument', 'Family', 'woodwind', 'istring', 'What family is it?'); +HTMLPurifier_ConfigSchema::defineAllowedValues('Instrument', 'Family', array( 'brass', 'woodwind', 'percussion', 'string', 'keyboard', 'electronic')); -CS::defineValueAliases('Instrument', 'Family', array( +HTMLPurifier_ConfigSchema::defineValueAliases('Instrument', 'Family', array( 'synth' => 'electronic')); -CS::defineNamespace('ReportCard', 'It is for grades.'); -CS::define('ReportCard', 'English', null, 'string/null', 'Grade from English class.'); -CS::define('ReportCard', 'Absences', 0, 'int', 'How many times missing from school?'); +HTMLPurifier_ConfigSchema::defineNamespace('ReportCard', 'It is for grades.'); +HTMLPurifier_ConfigSchema::define('ReportCard', 'English', null, 'string/null', 'Grade from English class.'); +HTMLPurifier_ConfigSchema::define('ReportCard', 'Absences', 0, 'int', 'How many times missing from school?'); ?> \ No newline at end of file diff --git a/tests/HTMLPurifier/ConfigTest.php b/tests/HTMLPurifier/ConfigTest.php index 787253f0..72023e5e 100644 --- a/tests/HTMLPurifier/ConfigTest.php +++ b/tests/HTMLPurifier/ConfigTest.php @@ -376,6 +376,84 @@ class HTMLPurifier_ConfigTest extends UnitTestCase } + function test_loadArrayFromForm() { + + CS::defineNamespace('Pancake', 'This should not be user customizable'); + CS::define('Pancake', 'Mix', 'buttermilk', 'string', 'Type of pancake mix to use.'); + CS::define('Pancake', 'Served', true, 'bool', 'But this is customizable by user.'); + CS::defineNamespace('Toppings', 'This is user customizable'); + CS::define('Toppings', 'Syrup', true, 'bool', 'Absolutely standard!'); + CS::define('Toppings', 'Flavor', 'maple', 'string', 'What flavor is the syrup?'); + CS::define('Toppings', 'Strawberries', 3, 'int', 'Quite delightful fruit.'); + CS::define('Toppings', 'Calories', 2000, 'int/null', 'Some things are best left unknown.'); + CS::define('Toppings', 'DefinitionID', null, 'string/null', 'Do not let this be set'); + CS::define('Toppings', 'DefinitionRev', 1, 'int', 'Do not let this be set'); + CS::define('Toppings', 'Protected', 1, 'int', 'Do not let this be set'); + + $get = array( + 'breakfast' => array( + 'Pancake.Mix' => 'nasty', + 'Pancake.Served' => '0', + 'Toppings.Syrup' => '0', + 'Toppings.Flavor' => "Bug\\'s juice", + 'Toppings.Strawberries' => '999', + 'Toppings.Calories' => '', + 'Null_Toppings.Calories' => '1', + 'Toppings.DefinitionID' => '', + 'Toppings.DefinitionRev' => '65', + 'Toppings.Protected' => '4', + ) + ); + + $config_expect = HTMLPurifier_Config::create(array( + 'Pancake.Served' => false, + 'Toppings.Syrup' => false, + 'Toppings.Flavor' => "Bug's juice", + 'Toppings.Strawberries' => 999, + 'Toppings.Calories' => null + )); + + $config_result = HTMLPurifier_Config::loadArrayFromForm($get, 'breakfast', array('Pancake.Served', 'Toppings', '-Toppings.Protected'), true); + + $this->assertEqual($config_expect, $config_result); + + + $get = array( + 'breakfast' => array( + 'Pancake.Mix' => 'n\\asty' + ) + ); + $config_expect = HTMLPurifier_Config::create(array( + 'Pancake.Mix' => 'n\\asty' + )); + $config_result = HTMLPurifier_Config::loadArrayFromForm($get, 'breakfast', true, false); + $this->assertEqual($config_expect, $config_result); + + } + + function test_getAllowedDirectivesForForm() { + CS::defineNamespace('Unused', 'Not mentioned, so deny'); + CS::define('Unused', 'Unused', 'Foobar', 'string', 'Not mentioned, do not allow'); + CS::defineNamespace('Partial', 'Some are mentioned, allow only those'); + CS::define('Partial', 'Allowed', true, 'bool', 'Mentioned, allowed'); + CS::define('Partial', 'Unused', 'Foobar', 'string', 'Not mentioned, do not allow'); + CS::defineNamespace('All', 'Entire namespace allowed, allow all unless...'); + CS::define('All', 'Allowed', true, 'bool', 'Not mentioned, allowed'); + CS::define('All', 'Blacklisted', 'Foobar', 'string', 'Specifically blacklisted'); + CS::define('All', 'DefinitionID', 'Foobar', 'string/null', 'Special case, auto-blacklisted'); + CS::define('All', 'DefinitionRev', 2, 'int', 'Special case, auto-blacklisted'); + + $input = array('Partial.Allowed', 'All', '-All.Blacklisted'); + $output = HTMLPurifier_Config::getAllowedDirectivesForForm($input); + $expect = array( + array('Partial', 'Allowed'), + array('All', 'Allowed') + ); + + $this->assertEqual($output, $expect); + + } + } ?> \ No newline at end of file diff --git a/tests/HTMLPurifier/HTMLModuleManagerTest.php b/tests/HTMLPurifier/HTMLModuleManagerTest.php index 4f94bc1b..b74df5f4 100644 --- a/tests/HTMLPurifier/HTMLModuleManagerTest.php +++ b/tests/HTMLPurifier/HTMLModuleManagerTest.php @@ -38,7 +38,7 @@ class HTMLPurifier_HTMLModuleManagerTest extends UnitTestCase $config = HTMLPurifier_Config::createDefault(); $config->set('HTML', 'Trusted', false); - $config->set('HTML', 'Doctype', 'Blank'); + $config->set('HTML', 'CustomDoctype', 'Blank'); $manager->setup($config); @@ -94,7 +94,7 @@ class HTMLPurifier_HTMLModuleManagerTest extends UnitTestCase $manager->registerModule($magic_module); $config = HTMLPurifier_Config::create(array( - 'HTML.Doctype' => 'Fantasy Inventory 1.0', + 'HTML.CustomDoctype' => 'Fantasy Inventory 1.0', 'HTML.AllowedModules' => 'Weapons' )); $manager->setup($config);