0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2025-01-03 05:11:52 +00:00

MOODLE-556: Added some types for MathML attributes to restrict use of CDATA

This commit is contained in:
Xavier Ripoll 2018-11-15 14:56:11 +01:00
parent 12b1110bf6
commit ad34dd3841
7 changed files with 268 additions and 12 deletions

View File

@ -0,0 +1,25 @@
<?php
/**
* Validates the MathML attribute character.
*/
class HTMLPurifier_AttrDef_MathML_Character extends HTMLPurifier_AttrDef
{
/**
* @param string $char
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($char, $config, $context)
{
if (mb_strlen($char) == 1 && strpos(' \t\n\r', $char) === false) {
return $char;
} elseif (preg_match('/&((#[0-9]+)|(#x[0-9A-Fa-f]+)|([0-9A-Za-z]+));/', $char)) {
return $char;
}
return false;
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Validates Color as defined by MathML.
*/
class HTMLPurifier_AttrDef_MathML_Color extends HTMLPurifier_AttrDef
{
// MathML 3 only accepts HTML4 color names + transparent
static protected $colornames = array(
'aqua',
'black',
'blue',
'fuchsia',
'gray',
'green',
'lime',
'maroon',
'navy',
'olive',
'purple',
'red',
'silver',
'teal',
'white',
'yellow',
'transparent'
);
public function validate($color, $config, $context)
{
$color = trim($color);
if (preg_match('/(#[0-9A-Fa-f]{3})|(#[0-9A-Fa-f]{6})/', $color) || in_array(strtolower($color), static::$colornames)) {
return $color;
}
return false;
}
}
// vim: et sw=4 sts=4

View File

@ -0,0 +1,36 @@
<?php
/**
* Validates the MathML type length (not to be confused with either HTML nor
* CSS's length).
*/
class HTMLPurifier_AttrDef_MathML_Length extends HTMLPurifier_AttrDef
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string);
// Optimizations
if ($string === '') {
return false;
}
if ($string === '0') {
return '0';
}
$length = HTMLPurifier_MathMLLength::make($string);
if (!$length->isValid()) {
return false;
}
return $length->toString();
}
}

View File

@ -50,10 +50,23 @@ class HTMLPurifier_AttrTypes
// "proprietary" types
$this->info['Class'] = new HTMLPurifier_AttrDef_HTML_Class();
$this->info['CSS'] = new HTMLPurifier_AttrDef_CSS();
// number is really a positive integer (one or more digits)
// FIXME: ^^ not always, see start and value of list items
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
// MathML types
$this->info['MathML_ID'] = new HTMLPurifier_AttrDef_MathML_ID();
$this->info['MathML_Length'] = new HTMLPurifier_AttrDef_MathML_Length();
$this->info['MathML_UnsignedInteger'] = new HTMLPurifier_AttrDef_Integer(false, true, true);
$this->info['MathML_PositiveInteger'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
$this->info['MathML_Integer'] = new HTMLPurifier_AttrDef_Integer(true, true, true);
$this->info['MathML_UnsignedNumber'] = new HTMLPurifier_AttrDef_CSS_Number(true);
$this->info['MathML_Number'] = new HTMLPurifier_AttrDef_CSS_Number(false);
$this->info['MathML_Character'] = new HTMLPurifier_AttrDef_MathML_Character();
$this->info['MathML_Color'] = new HTMLPurifier_AttrDef_MathML_Color();
}
private static function makeEnum($in)

View File

@ -82,10 +82,10 @@ class HTMLPurifier_HTMLModule_MathML extends HTMLPurifier_HTMLModule
$E['XLINK.prefix'] . ':type' => 'CDATA',
'xml:lang' => 'CDATA',
'xml:space' => 'Enum#default,preserve',
'id' => new HTMLPurifier_AttrDef_MathML_ID(), // MathML allows multiple elements with same ID
'xref' => new HTMLPurifier_AttrDef_MathML_ID(),
'id' => 'MathML_ID', // MathML allows multiple elements with same ID
'xref' => 'MathML_ID',
'class' => 'Class',
'style' => new HTMLPurifier_AttrDef_CSS(),
'style' => 'CSS',
'href' => 'URI',
'other' => 'CDATA',
),
@ -1442,16 +1442,16 @@ class HTMLPurifier_HTMLModule_MathML extends HTMLPurifier_HTMLModule
$E['mpadded-length'] = 'CDATA';
$E['linestyle'] = 'Enum#none,solid,dashed';
$E['columnalignstyle'] = 'Enum#left,center,right';
$E['unsigned-integer'] = 'CDATA';
$E['integer'] = 'CDATA';
$E['number'] = 'CDATA';
$E['character'] = 'CDATA';
$E['color'] = 'CDATA';
$E['positive-integer'] = 'CDATA';
$E['unsigned-integer'] = 'MathML_UnsignedInteger';
$E['integer'] = 'MathML_Integer';
$E['number'] = 'MathML_Number';
$E['character'] = 'MathML_Character';
$E['color'] = 'MathML_Color';
$E['positive-integer'] = 'MathML_PositiveInteger';
$E['token.content'] = '#PCDATA|mglyph|malignmark';
$E['length'] = 'CDATA';
$E['length'] = 'MathML_Length';
$E['DeprecatedTokenAtt'] = array(
'fontfamily' => 'CDATA',
'fontweight' => 'Enum#normal,bold',
@ -2167,7 +2167,8 @@ class HTMLPurifier_HTMLModule_MathML extends HTMLPurifier_HTMLModule
array_merge(
$CCPAtt,
array(
'actiontype*' => 'CDATA',
// Using 'actiontype*' removes maction element altogether
'actiontype' => 'CDATA',
'selection' => $E['positive-integer'],
)
)

View File

@ -81,7 +81,8 @@ class HTMLPurifier_Length
if (!ctype_lower($this->unit)) {
$this->unit = strtolower($this->unit);
}
if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) {
if (!isset(static::$allowedUnits[$this->unit]) &&
!(isset(static::$allowedUnits['']) && $this->unit === false)) {
return false;
}
// Hack:

View File

@ -0,0 +1,136 @@
<?php
/**
* Represents a length in MathML. These admit namedspace values.
*/
class HTMLPurifier_MathMLLength extends HTMLPurifier_Length
{
/**
* One of the specified namedspaces.
* @type string
*/
protected $namedspace;
/**
* Array Lookup array of namedspaces recognized by MathML
* @type array
*/
protected static $allowedNamedspaces = array(
'veryverythinmathspace' => true,
'verythinmathspace' => true,
'thinmathspace' => true,
'mediummathspace' => true,
'thickmathspace' => true,
'verythickmathspace' => true,
'veryverythickmathspace' => true,
'negativeveryverythinmathspace' => true,
'negativeverythinmathspace' => true,
'negativethinmathspace' => true,
'negativemediummathspace' => true,
'negativethickmathspace' => true,
'negativeverythickmathspace' => true,
'negativeveryverythickmathspace' => true
);
/**
* Array Lookup array of units recognized by MathML.
* @note This is a restriction of HTMLPurifier_Length's allowed units.
* @type array
*/
protected static $allowedUnits = array(
'em' => true, 'ex' => true, 'px' => true, 'in' => true,
'cm' => true, 'mm' => true, 'pt' => true, 'pc' => true,
'%' => true, '' => true
);
/**
* @param string $n Magnitude
* @param bool|string $u Unit
*/
public function __construct($n = '0', $u = false, $namedspace = '')
{
if ($namedspace) {
$this->namedspace = strtolower($namedspace);
} else {
$this->n = (string) $n;
$this->unit = $u !== false ? (string) $u : false;
}
}
/**
* @param string $s Unit string, like '2em' or '3.4in', or namedspace
* @return HTMLPurifier_MathMLLength
* @warning Does not perform validation.
*/
public static function make($s)
{
if ($s instanceof HTMLPurifier_MathMLLength) {
return $s;
}
if (isset(HTMLPurifier_MathMLLength::$allowedNamedspaces[trim($s)])) {
return new HTMLPurifier_MathMLLength('0', false, $s);
}
$length = HTMLPurifier_Length::make($s);
return new HTMLPurifier_MathMLLength($length->n, $length->unit);
}
/**
* Validates the number and unit or namedspace.
* @return bool
*/
protected function validate()
{
if (isset(HTMLPurifier_MathMLLength::$allowedNamedspaces[$this->namedspace])) {
return true;
}
return parent::validate();
}
/**
* Returns string representation of number.
* @return string
*/
public function toString()
{
if (!$this->isValid()) {
return false;
}
if ($this->namedspace) {
return $this->namedspace;
}
return parent::toString();
}
/**
* Retrieves the namedspace.
* @return string
*/
public function getNamedspace()
{
return $this->namedspace;
}
/**
* Compares two lengths, and returns 1 if greater, -1 if less, 0 if equal
* and null if not comparable.
* @param HTMLPurifier_Length $l
* @return int
* @warning If both values are too large or small, this calculation will
* not work properly
*/
public function compareTo($l)
{
if ($l === false) {
return false;
}
if ($this->namedspace || $l->namedspace) {
if ($this->namedspace === $l->namedspace) {
return 0;
} else {
return null;
}
}
return parent::compareTo($l);
}
}