diff options
author | Nicolas Lœuillet <nicolas@loeuillet.org> | 2014-02-21 15:57:10 +0100 |
---|---|---|
committer | Nicolas Lœuillet <nicolas@loeuillet.org> | 2014-02-21 15:57:10 +0100 |
commit | 99679d06884120c57f43b44e55e03595f1f87bed (patch) | |
tree | a3f2a1aa1afdaeca1386d0c6e8a75344fd2241fb /inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS | |
parent | 655214ab30ee84884dc408488b85586f36263fcb (diff) | |
parent | d3b47e94705e17b3ba3529cbb1dc6efe69c5d2b7 (diff) | |
download | wallabag-99679d06884120c57f43b44e55e03595f1f87bed.tar.gz wallabag-99679d06884120c57f43b44e55e03595f1f87bed.tar.zst wallabag-99679d06884120c57f43b44e55e03595f1f87bed.zip |
Merge pull request #481 from wallabag/dev1.5.2
1.5.2
Diffstat (limited to 'inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS')
19 files changed, 1633 insertions, 0 deletions
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php new file mode 100644 index 00000000..1a30e8fe --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/AlphaValue.php | |||
@@ -0,0 +1,34 @@ | |||
1 | <?php | ||
2 | |||
3 | class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number | ||
4 | { | ||
5 | |||
6 | public function __construct() | ||
7 | { | ||
8 | parent::__construct(false); // opacity is non-negative, but we will clamp it | ||
9 | } | ||
10 | |||
11 | /** | ||
12 | * @param string $number | ||
13 | * @param HTMLPurifier_Config $config | ||
14 | * @param HTMLPurifier_Context $context | ||
15 | * @return string | ||
16 | */ | ||
17 | public function validate($number, $config, $context) | ||
18 | { | ||
19 | $result = parent::validate($number, $config, $context); | ||
20 | if ($result === false) { | ||
21 | return $result; | ||
22 | } | ||
23 | $float = (float)$result; | ||
24 | if ($float < 0.0) { | ||
25 | $result = '0'; | ||
26 | } | ||
27 | if ($float > 1.0) { | ||
28 | $result = '1'; | ||
29 | } | ||
30 | return $result; | ||
31 | } | ||
32 | } | ||
33 | |||
34 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php new file mode 100644 index 00000000..ecd6e276 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php | |||
@@ -0,0 +1,111 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates shorthand CSS property background. | ||
5 | * @warning Does not support url tokens that have internal spaces. | ||
6 | */ | ||
7 | class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef | ||
8 | { | ||
9 | |||
10 | /** | ||
11 | * Local copy of component validators. | ||
12 | * @type HTMLPurifier_AttrDef[] | ||
13 | * @note See HTMLPurifier_AttrDef_Font::$info for a similar impl. | ||
14 | */ | ||
15 | protected $info; | ||
16 | |||
17 | /** | ||
18 | * @param HTMLPurifier_Config $config | ||
19 | */ | ||
20 | public function __construct($config) | ||
21 | { | ||
22 | $def = $config->getCSSDefinition(); | ||
23 | $this->info['background-color'] = $def->info['background-color']; | ||
24 | $this->info['background-image'] = $def->info['background-image']; | ||
25 | $this->info['background-repeat'] = $def->info['background-repeat']; | ||
26 | $this->info['background-attachment'] = $def->info['background-attachment']; | ||
27 | $this->info['background-position'] = $def->info['background-position']; | ||
28 | } | ||
29 | |||
30 | /** | ||
31 | * @param string $string | ||
32 | * @param HTMLPurifier_Config $config | ||
33 | * @param HTMLPurifier_Context $context | ||
34 | * @return bool|string | ||
35 | */ | ||
36 | public function validate($string, $config, $context) | ||
37 | { | ||
38 | // regular pre-processing | ||
39 | $string = $this->parseCDATA($string); | ||
40 | if ($string === '') { | ||
41 | return false; | ||
42 | } | ||
43 | |||
44 | // munge rgb() decl if necessary | ||
45 | $string = $this->mungeRgb($string); | ||
46 | |||
47 | // assumes URI doesn't have spaces in it | ||
48 | $bits = explode(' ', $string); // bits to process | ||
49 | |||
50 | $caught = array(); | ||
51 | $caught['color'] = false; | ||
52 | $caught['image'] = false; | ||
53 | $caught['repeat'] = false; | ||
54 | $caught['attachment'] = false; | ||
55 | $caught['position'] = false; | ||
56 | |||
57 | $i = 0; // number of catches | ||
58 | |||
59 | foreach ($bits as $bit) { | ||
60 | if ($bit === '') { | ||
61 | continue; | ||
62 | } | ||
63 | foreach ($caught as $key => $status) { | ||
64 | if ($key != 'position') { | ||
65 | if ($status !== false) { | ||
66 | continue; | ||
67 | } | ||
68 | $r = $this->info['background-' . $key]->validate($bit, $config, $context); | ||
69 | } else { | ||
70 | $r = $bit; | ||
71 | } | ||
72 | if ($r === false) { | ||
73 | continue; | ||
74 | } | ||
75 | if ($key == 'position') { | ||
76 | if ($caught[$key] === false) { | ||
77 | $caught[$key] = ''; | ||
78 | } | ||
79 | $caught[$key] .= $r . ' '; | ||
80 | } else { | ||
81 | $caught[$key] = $r; | ||
82 | } | ||
83 | $i++; | ||
84 | break; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | if (!$i) { | ||
89 | return false; | ||
90 | } | ||
91 | if ($caught['position'] !== false) { | ||
92 | $caught['position'] = $this->info['background-position']-> | ||
93 | validate($caught['position'], $config, $context); | ||
94 | } | ||
95 | |||
96 | $ret = array(); | ||
97 | foreach ($caught as $value) { | ||
98 | if ($value === false) { | ||
99 | continue; | ||
100 | } | ||
101 | $ret[] = $value; | ||
102 | } | ||
103 | |||
104 | if (empty($ret)) { | ||
105 | return false; | ||
106 | } | ||
107 | return implode(' ', $ret); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php new file mode 100644 index 00000000..f95de5bb --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php | |||
@@ -0,0 +1,157 @@ | |||
1 | <?php | ||
2 | |||
3 | /* W3C says: | ||
4 | [ // adjective and number must be in correct order, even if | ||
5 | // you could switch them without introducing ambiguity. | ||
6 | // some browsers support that syntax | ||
7 | [ | ||
8 | <percentage> | <length> | left | center | right | ||
9 | ] | ||
10 | [ | ||
11 | <percentage> | <length> | top | center | bottom | ||
12 | ]? | ||
13 | ] | | ||
14 | [ // this signifies that the vertical and horizontal adjectives | ||
15 | // can be arbitrarily ordered, however, there can only be two, | ||
16 | // one of each, or none at all | ||
17 | [ | ||
18 | left | center | right | ||
19 | ] || | ||
20 | [ | ||
21 | top | center | bottom | ||
22 | ] | ||
23 | ] | ||
24 | top, left = 0% | ||
25 | center, (none) = 50% | ||
26 | bottom, right = 100% | ||
27 | */ | ||
28 | |||
29 | /* QuirksMode says: | ||
30 | keyword + length/percentage must be ordered correctly, as per W3C | ||
31 | |||
32 | Internet Explorer and Opera, however, support arbitrary ordering. We | ||
33 | should fix it up. | ||
34 | |||
35 | Minor issue though, not strictly necessary. | ||
36 | */ | ||
37 | |||
38 | // control freaks may appreciate the ability to convert these to | ||
39 | // percentages or something, but it's not necessary | ||
40 | |||
41 | /** | ||
42 | * Validates the value of background-position. | ||
43 | */ | ||
44 | class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef | ||
45 | { | ||
46 | |||
47 | /** | ||
48 | * @type HTMLPurifier_AttrDef_CSS_Length | ||
49 | */ | ||
50 | protected $length; | ||
51 | |||
52 | /** | ||
53 | * @type HTMLPurifier_AttrDef_CSS_Percentage | ||
54 | */ | ||
55 | protected $percentage; | ||
56 | |||
57 | public function __construct() | ||
58 | { | ||
59 | $this->length = new HTMLPurifier_AttrDef_CSS_Length(); | ||
60 | $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage(); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * @param string $string | ||
65 | * @param HTMLPurifier_Config $config | ||
66 | * @param HTMLPurifier_Context $context | ||
67 | * @return bool|string | ||
68 | */ | ||
69 | public function validate($string, $config, $context) | ||
70 | { | ||
71 | $string = $this->parseCDATA($string); | ||
72 | $bits = explode(' ', $string); | ||
73 | |||
74 | $keywords = array(); | ||
75 | $keywords['h'] = false; // left, right | ||
76 | $keywords['v'] = false; // top, bottom | ||
77 | $keywords['ch'] = false; // center (first word) | ||
78 | $keywords['cv'] = false; // center (second word) | ||
79 | $measures = array(); | ||
80 | |||
81 | $i = 0; | ||
82 | |||
83 | $lookup = array( | ||
84 | 'top' => 'v', | ||
85 | 'bottom' => 'v', | ||
86 | 'left' => 'h', | ||
87 | 'right' => 'h', | ||
88 | 'center' => 'c' | ||
89 | ); | ||
90 | |||
91 | foreach ($bits as $bit) { | ||
92 | if ($bit === '') { | ||
93 | continue; | ||
94 | } | ||
95 | |||
96 | // test for keyword | ||
97 | $lbit = ctype_lower($bit) ? $bit : strtolower($bit); | ||
98 | if (isset($lookup[$lbit])) { | ||
99 | $status = $lookup[$lbit]; | ||
100 | if ($status == 'c') { | ||
101 | if ($i == 0) { | ||
102 | $status = 'ch'; | ||
103 | } else { | ||
104 | $status = 'cv'; | ||
105 | } | ||
106 | } | ||
107 | $keywords[$status] = $lbit; | ||
108 | $i++; | ||
109 | } | ||
110 | |||
111 | // test for length | ||
112 | $r = $this->length->validate($bit, $config, $context); | ||
113 | if ($r !== false) { | ||
114 | $measures[] = $r; | ||
115 | $i++; | ||
116 | } | ||
117 | |||
118 | // test for percentage | ||
119 | $r = $this->percentage->validate($bit, $config, $context); | ||
120 | if ($r !== false) { | ||
121 | $measures[] = $r; | ||
122 | $i++; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | if (!$i) { | ||
127 | return false; | ||
128 | } // no valid values were caught | ||
129 | |||
130 | $ret = array(); | ||
131 | |||
132 | // first keyword | ||
133 | if ($keywords['h']) { | ||
134 | $ret[] = $keywords['h']; | ||
135 | } elseif ($keywords['ch']) { | ||
136 | $ret[] = $keywords['ch']; | ||
137 | $keywords['cv'] = false; // prevent re-use: center = center center | ||
138 | } elseif (count($measures)) { | ||
139 | $ret[] = array_shift($measures); | ||
140 | } | ||
141 | |||
142 | if ($keywords['v']) { | ||
143 | $ret[] = $keywords['v']; | ||
144 | } elseif ($keywords['cv']) { | ||
145 | $ret[] = $keywords['cv']; | ||
146 | } elseif (count($measures)) { | ||
147 | $ret[] = array_shift($measures); | ||
148 | } | ||
149 | |||
150 | if (empty($ret)) { | ||
151 | return false; | ||
152 | } | ||
153 | return implode(' ', $ret); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Border.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Border.php new file mode 100644 index 00000000..bd310ff2 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Border.php | |||
@@ -0,0 +1,56 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates the border property as defined by CSS. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * Local copy of properties this property is shorthand for. | ||
11 | * @type HTMLPurifier_AttrDef[] | ||
12 | */ | ||
13 | protected $info = array(); | ||
14 | |||
15 | /** | ||
16 | * @param HTMLPurifier_Config $config | ||
17 | */ | ||
18 | public function __construct($config) | ||
19 | { | ||
20 | $def = $config->getCSSDefinition(); | ||
21 | $this->info['border-width'] = $def->info['border-width']; | ||
22 | $this->info['border-style'] = $def->info['border-style']; | ||
23 | $this->info['border-top-color'] = $def->info['border-top-color']; | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * @param string $string | ||
28 | * @param HTMLPurifier_Config $config | ||
29 | * @param HTMLPurifier_Context $context | ||
30 | * @return bool|string | ||
31 | */ | ||
32 | public function validate($string, $config, $context) | ||
33 | { | ||
34 | $string = $this->parseCDATA($string); | ||
35 | $string = $this->mungeRgb($string); | ||
36 | $bits = explode(' ', $string); | ||
37 | $done = array(); // segments we've finished | ||
38 | $ret = ''; // return value | ||
39 | foreach ($bits as $bit) { | ||
40 | foreach ($this->info as $propname => $validator) { | ||
41 | if (isset($done[$propname])) { | ||
42 | continue; | ||
43 | } | ||
44 | $r = $validator->validate($bit, $config, $context); | ||
45 | if ($r !== false) { | ||
46 | $ret .= $r . ' '; | ||
47 | $done[$propname] = true; | ||
48 | break; | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | return rtrim($ret); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Color.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Color.php new file mode 100644 index 00000000..e553c65e --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Color.php | |||
@@ -0,0 +1,105 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates Color as defined by CSS. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * @param string $color | ||
11 | * @param HTMLPurifier_Config $config | ||
12 | * @param HTMLPurifier_Context $context | ||
13 | * @return bool|string | ||
14 | */ | ||
15 | public function validate($color, $config, $context) | ||
16 | { | ||
17 | static $colors = null; | ||
18 | if ($colors === null) { | ||
19 | $colors = $config->get('Core.ColorKeywords'); | ||
20 | } | ||
21 | |||
22 | $color = trim($color); | ||
23 | if ($color === '') { | ||
24 | return false; | ||
25 | } | ||
26 | |||
27 | $lower = strtolower($color); | ||
28 | if (isset($colors[$lower])) { | ||
29 | return $colors[$lower]; | ||
30 | } | ||
31 | |||
32 | if (strpos($color, 'rgb(') !== false) { | ||
33 | // rgb literal handling | ||
34 | $length = strlen($color); | ||
35 | if (strpos($color, ')') !== $length - 1) { | ||
36 | return false; | ||
37 | } | ||
38 | $triad = substr($color, 4, $length - 4 - 1); | ||
39 | $parts = explode(',', $triad); | ||
40 | if (count($parts) !== 3) { | ||
41 | return false; | ||
42 | } | ||
43 | $type = false; // to ensure that they're all the same type | ||
44 | $new_parts = array(); | ||
45 | foreach ($parts as $part) { | ||
46 | $part = trim($part); | ||
47 | if ($part === '') { | ||
48 | return false; | ||
49 | } | ||
50 | $length = strlen($part); | ||
51 | if ($part[$length - 1] === '%') { | ||
52 | // handle percents | ||
53 | if (!$type) { | ||
54 | $type = 'percentage'; | ||
55 | } elseif ($type !== 'percentage') { | ||
56 | return false; | ||
57 | } | ||
58 | $num = (float)substr($part, 0, $length - 1); | ||
59 | if ($num < 0) { | ||
60 | $num = 0; | ||
61 | } | ||
62 | if ($num > 100) { | ||
63 | $num = 100; | ||
64 | } | ||
65 | $new_parts[] = "$num%"; | ||
66 | } else { | ||
67 | // handle integers | ||
68 | if (!$type) { | ||
69 | $type = 'integer'; | ||
70 | } elseif ($type !== 'integer') { | ||
71 | return false; | ||
72 | } | ||
73 | $num = (int)$part; | ||
74 | if ($num < 0) { | ||
75 | $num = 0; | ||
76 | } | ||
77 | if ($num > 255) { | ||
78 | $num = 255; | ||
79 | } | ||
80 | $new_parts[] = (string)$num; | ||
81 | } | ||
82 | } | ||
83 | $new_triad = implode(',', $new_parts); | ||
84 | $color = "rgb($new_triad)"; | ||
85 | } else { | ||
86 | // hexadecimal handling | ||
87 | if ($color[0] === '#') { | ||
88 | $hex = substr($color, 1); | ||
89 | } else { | ||
90 | $hex = $color; | ||
91 | $color = '#' . $color; | ||
92 | } | ||
93 | $length = strlen($hex); | ||
94 | if ($length !== 3 && $length !== 6) { | ||
95 | return false; | ||
96 | } | ||
97 | if (!ctype_xdigit($hex)) { | ||
98 | return false; | ||
99 | } | ||
100 | } | ||
101 | return $color; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Composite.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Composite.php new file mode 100644 index 00000000..38900232 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Composite.php | |||
@@ -0,0 +1,48 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Allows multiple validators to attempt to validate attribute. | ||
5 | * | ||
6 | * Composite is just what it sounds like: a composite of many validators. | ||
7 | * This means that multiple HTMLPurifier_AttrDef objects will have a whack | ||
8 | * at the string. If one of them passes, that's what is returned. This is | ||
9 | * especially useful for CSS values, which often are a choice between | ||
10 | * an enumerated set of predefined values or a flexible data type. | ||
11 | */ | ||
12 | class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef | ||
13 | { | ||
14 | |||
15 | /** | ||
16 | * List of objects that may process strings. | ||
17 | * @type HTMLPurifier_AttrDef[] | ||
18 | * @todo Make protected | ||
19 | */ | ||
20 | public $defs; | ||
21 | |||
22 | /** | ||
23 | * @param HTMLPurifier_AttrDef[] $defs List of HTMLPurifier_AttrDef objects | ||
24 | */ | ||
25 | public function __construct($defs) | ||
26 | { | ||
27 | $this->defs = $defs; | ||
28 | } | ||
29 | |||
30 | /** | ||
31 | * @param string $string | ||
32 | * @param HTMLPurifier_Config $config | ||
33 | * @param HTMLPurifier_Context $context | ||
34 | * @return bool|string | ||
35 | */ | ||
36 | public function validate($string, $config, $context) | ||
37 | { | ||
38 | foreach ($this->defs as $i => $def) { | ||
39 | $result = $this->defs[$i]->validate($string, $config, $context); | ||
40 | if ($result !== false) { | ||
41 | return $result; | ||
42 | } | ||
43 | } | ||
44 | return false; | ||
45 | } | ||
46 | } | ||
47 | |||
48 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php new file mode 100644 index 00000000..ff0d897e --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php | |||
@@ -0,0 +1,44 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Decorator which enables CSS properties to be disabled for specific elements. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | /** | ||
9 | * @type HTMLPurifier_AttrDef | ||
10 | */ | ||
11 | public $def; | ||
12 | /** | ||
13 | * @type string | ||
14 | */ | ||
15 | public $element; | ||
16 | |||
17 | /** | ||
18 | * @param HTMLPurifier_AttrDef $def Definition to wrap | ||
19 | * @param string $element Element to deny | ||
20 | */ | ||
21 | public function __construct($def, $element) | ||
22 | { | ||
23 | $this->def = $def; | ||
24 | $this->element = $element; | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * Checks if CurrentToken is set and equal to $this->element | ||
29 | * @param string $string | ||
30 | * @param HTMLPurifier_Config $config | ||
31 | * @param HTMLPurifier_Context $context | ||
32 | * @return bool|string | ||
33 | */ | ||
34 | public function validate($string, $config, $context) | ||
35 | { | ||
36 | $token = $context->get('CurrentToken', true); | ||
37 | if ($token && $token->name == $this->element) { | ||
38 | return false; | ||
39 | } | ||
40 | return $this->def->validate($string, $config, $context); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Filter.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Filter.php new file mode 100644 index 00000000..019722a4 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Filter.php | |||
@@ -0,0 +1,77 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Microsoft's proprietary filter: CSS property | ||
5 | * @note Currently supports the alpha filter. In the future, this will | ||
6 | * probably need an extensible framework | ||
7 | */ | ||
8 | class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef | ||
9 | { | ||
10 | /** | ||
11 | * @type HTMLPurifier_AttrDef_Integer | ||
12 | */ | ||
13 | protected $intValidator; | ||
14 | |||
15 | public function __construct() | ||
16 | { | ||
17 | $this->intValidator = new HTMLPurifier_AttrDef_Integer(); | ||
18 | } | ||
19 | |||
20 | /** | ||
21 | * @param string $value | ||
22 | * @param HTMLPurifier_Config $config | ||
23 | * @param HTMLPurifier_Context $context | ||
24 | * @return bool|string | ||
25 | */ | ||
26 | public function validate($value, $config, $context) | ||
27 | { | ||
28 | $value = $this->parseCDATA($value); | ||
29 | if ($value === 'none') { | ||
30 | return $value; | ||
31 | } | ||
32 | // if we looped this we could support multiple filters | ||
33 | $function_length = strcspn($value, '('); | ||
34 | $function = trim(substr($value, 0, $function_length)); | ||
35 | if ($function !== 'alpha' && | ||
36 | $function !== 'Alpha' && | ||
37 | $function !== 'progid:DXImageTransform.Microsoft.Alpha' | ||
38 | ) { | ||
39 | return false; | ||
40 | } | ||
41 | $cursor = $function_length + 1; | ||
42 | $parameters_length = strcspn($value, ')', $cursor); | ||
43 | $parameters = substr($value, $cursor, $parameters_length); | ||
44 | $params = explode(',', $parameters); | ||
45 | $ret_params = array(); | ||
46 | $lookup = array(); | ||
47 | foreach ($params as $param) { | ||
48 | list($key, $value) = explode('=', $param); | ||
49 | $key = trim($key); | ||
50 | $value = trim($value); | ||
51 | if (isset($lookup[$key])) { | ||
52 | continue; | ||
53 | } | ||
54 | if ($key !== 'opacity') { | ||
55 | continue; | ||
56 | } | ||
57 | $value = $this->intValidator->validate($value, $config, $context); | ||
58 | if ($value === false) { | ||
59 | continue; | ||
60 | } | ||
61 | $int = (int)$value; | ||
62 | if ($int > 100) { | ||
63 | $value = '100'; | ||
64 | } | ||
65 | if ($int < 0) { | ||
66 | $value = '0'; | ||
67 | } | ||
68 | $ret_params[] = "$key=$value"; | ||
69 | $lookup[$key] = true; | ||
70 | } | ||
71 | $ret_parameters = implode(',', $ret_params); | ||
72 | $ret_function = "$function($ret_parameters)"; | ||
73 | return $ret_function; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Font.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Font.php new file mode 100644 index 00000000..b9b63f8e --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Font.php | |||
@@ -0,0 +1,176 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates shorthand CSS property font. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * Local copy of validators | ||
11 | * @type HTMLPurifier_AttrDef[] | ||
12 | * @note If we moved specific CSS property definitions to their own | ||
13 | * classes instead of having them be assembled at run time by | ||
14 | * CSSDefinition, this wouldn't be necessary. We'd instantiate | ||
15 | * our own copies. | ||
16 | */ | ||
17 | protected $info = array(); | ||
18 | |||
19 | /** | ||
20 | * @param HTMLPurifier_Config $config | ||
21 | */ | ||
22 | public function __construct($config) | ||
23 | { | ||
24 | $def = $config->getCSSDefinition(); | ||
25 | $this->info['font-style'] = $def->info['font-style']; | ||
26 | $this->info['font-variant'] = $def->info['font-variant']; | ||
27 | $this->info['font-weight'] = $def->info['font-weight']; | ||
28 | $this->info['font-size'] = $def->info['font-size']; | ||
29 | $this->info['line-height'] = $def->info['line-height']; | ||
30 | $this->info['font-family'] = $def->info['font-family']; | ||
31 | } | ||
32 | |||
33 | /** | ||
34 | * @param string $string | ||
35 | * @param HTMLPurifier_Config $config | ||
36 | * @param HTMLPurifier_Context $context | ||
37 | * @return bool|string | ||
38 | */ | ||
39 | public function validate($string, $config, $context) | ||
40 | { | ||
41 | static $system_fonts = array( | ||
42 | 'caption' => true, | ||
43 | 'icon' => true, | ||
44 | 'menu' => true, | ||
45 | 'message-box' => true, | ||
46 | 'small-caption' => true, | ||
47 | 'status-bar' => true | ||
48 | ); | ||
49 | |||
50 | // regular pre-processing | ||
51 | $string = $this->parseCDATA($string); | ||
52 | if ($string === '') { | ||
53 | return false; | ||
54 | } | ||
55 | |||
56 | // check if it's one of the keywords | ||
57 | $lowercase_string = strtolower($string); | ||
58 | if (isset($system_fonts[$lowercase_string])) { | ||
59 | return $lowercase_string; | ||
60 | } | ||
61 | |||
62 | $bits = explode(' ', $string); // bits to process | ||
63 | $stage = 0; // this indicates what we're looking for | ||
64 | $caught = array(); // which stage 0 properties have we caught? | ||
65 | $stage_1 = array('font-style', 'font-variant', 'font-weight'); | ||
66 | $final = ''; // output | ||
67 | |||
68 | for ($i = 0, $size = count($bits); $i < $size; $i++) { | ||
69 | if ($bits[$i] === '') { | ||
70 | continue; | ||
71 | } | ||
72 | switch ($stage) { | ||
73 | case 0: // attempting to catch font-style, font-variant or font-weight | ||
74 | foreach ($stage_1 as $validator_name) { | ||
75 | if (isset($caught[$validator_name])) { | ||
76 | continue; | ||
77 | } | ||
78 | $r = $this->info[$validator_name]->validate( | ||
79 | $bits[$i], | ||
80 | $config, | ||
81 | $context | ||
82 | ); | ||
83 | if ($r !== false) { | ||
84 | $final .= $r . ' '; | ||
85 | $caught[$validator_name] = true; | ||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | // all three caught, continue on | ||
90 | if (count($caught) >= 3) { | ||
91 | $stage = 1; | ||
92 | } | ||
93 | if ($r !== false) { | ||
94 | break; | ||
95 | } | ||
96 | case 1: // attempting to catch font-size and perhaps line-height | ||
97 | $found_slash = false; | ||
98 | if (strpos($bits[$i], '/') !== false) { | ||
99 | list($font_size, $line_height) = | ||
100 | explode('/', $bits[$i]); | ||
101 | if ($line_height === '') { | ||
102 | // ooh, there's a space after the slash! | ||
103 | $line_height = false; | ||
104 | $found_slash = true; | ||
105 | } | ||
106 | } else { | ||
107 | $font_size = $bits[$i]; | ||
108 | $line_height = false; | ||
109 | } | ||
110 | $r = $this->info['font-size']->validate( | ||
111 | $font_size, | ||
112 | $config, | ||
113 | $context | ||
114 | ); | ||
115 | if ($r !== false) { | ||
116 | $final .= $r; | ||
117 | // attempt to catch line-height | ||
118 | if ($line_height === false) { | ||
119 | // we need to scroll forward | ||
120 | for ($j = $i + 1; $j < $size; $j++) { | ||
121 | if ($bits[$j] === '') { | ||
122 | continue; | ||
123 | } | ||
124 | if ($bits[$j] === '/') { | ||
125 | if ($found_slash) { | ||
126 | return false; | ||
127 | } else { | ||
128 | $found_slash = true; | ||
129 | continue; | ||
130 | } | ||
131 | } | ||
132 | $line_height = $bits[$j]; | ||
133 | break; | ||
134 | } | ||
135 | } else { | ||
136 | // slash already found | ||
137 | $found_slash = true; | ||
138 | $j = $i; | ||
139 | } | ||
140 | if ($found_slash) { | ||
141 | $i = $j; | ||
142 | $r = $this->info['line-height']->validate( | ||
143 | $line_height, | ||
144 | $config, | ||
145 | $context | ||
146 | ); | ||
147 | if ($r !== false) { | ||
148 | $final .= '/' . $r; | ||
149 | } | ||
150 | } | ||
151 | $final .= ' '; | ||
152 | $stage = 2; | ||
153 | break; | ||
154 | } | ||
155 | return false; | ||
156 | case 2: // attempting to catch font-family | ||
157 | $font_family = | ||
158 | implode(' ', array_slice($bits, $i, $size - $i)); | ||
159 | $r = $this->info['font-family']->validate( | ||
160 | $font_family, | ||
161 | $config, | ||
162 | $context | ||
163 | ); | ||
164 | if ($r !== false) { | ||
165 | $final .= $r . ' '; | ||
166 | // processing completed successfully | ||
167 | return rtrim($final); | ||
168 | } | ||
169 | return false; | ||
170 | } | ||
171 | } | ||
172 | return false; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php new file mode 100644 index 00000000..f9af36d7 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php | |||
@@ -0,0 +1,219 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a font family list according to CSS spec | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | protected $mask = null; | ||
10 | |||
11 | public function __construct() | ||
12 | { | ||
13 | $this->mask = '_- '; | ||
14 | for ($c = 'a'; $c <= 'z'; $c++) { | ||
15 | $this->mask .= $c; | ||
16 | } | ||
17 | for ($c = 'A'; $c <= 'Z'; $c++) { | ||
18 | $this->mask .= $c; | ||
19 | } | ||
20 | for ($c = '0'; $c <= '9'; $c++) { | ||
21 | $this->mask .= $c; | ||
22 | } // cast-y, but should be fine | ||
23 | // special bytes used by UTF-8 | ||
24 | for ($i = 0x80; $i <= 0xFF; $i++) { | ||
25 | // We don't bother excluding invalid bytes in this range, | ||
26 | // because the our restriction of well-formed UTF-8 will | ||
27 | // prevent these from ever occurring. | ||
28 | $this->mask .= chr($i); | ||
29 | } | ||
30 | |||
31 | /* | ||
32 | PHP's internal strcspn implementation is | ||
33 | O(length of string * length of mask), making it inefficient | ||
34 | for large masks. However, it's still faster than | ||
35 | preg_match 8) | ||
36 | for (p = s1;;) { | ||
37 | spanp = s2; | ||
38 | do { | ||
39 | if (*spanp == c || p == s1_end) { | ||
40 | return p - s1; | ||
41 | } | ||
42 | } while (spanp++ < (s2_end - 1)); | ||
43 | c = *++p; | ||
44 | } | ||
45 | */ | ||
46 | // possible optimization: invert the mask. | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * @param string $string | ||
51 | * @param HTMLPurifier_Config $config | ||
52 | * @param HTMLPurifier_Context $context | ||
53 | * @return bool|string | ||
54 | */ | ||
55 | public function validate($string, $config, $context) | ||
56 | { | ||
57 | static $generic_names = array( | ||
58 | 'serif' => true, | ||
59 | 'sans-serif' => true, | ||
60 | 'monospace' => true, | ||
61 | 'fantasy' => true, | ||
62 | 'cursive' => true | ||
63 | ); | ||
64 | $allowed_fonts = $config->get('CSS.AllowedFonts'); | ||
65 | |||
66 | // assume that no font names contain commas in them | ||
67 | $fonts = explode(',', $string); | ||
68 | $final = ''; | ||
69 | foreach ($fonts as $font) { | ||
70 | $font = trim($font); | ||
71 | if ($font === '') { | ||
72 | continue; | ||
73 | } | ||
74 | // match a generic name | ||
75 | if (isset($generic_names[$font])) { | ||
76 | if ($allowed_fonts === null || isset($allowed_fonts[$font])) { | ||
77 | $final .= $font . ', '; | ||
78 | } | ||
79 | continue; | ||
80 | } | ||
81 | // match a quoted name | ||
82 | if ($font[0] === '"' || $font[0] === "'") { | ||
83 | $length = strlen($font); | ||
84 | if ($length <= 2) { | ||
85 | continue; | ||
86 | } | ||
87 | $quote = $font[0]; | ||
88 | if ($font[$length - 1] !== $quote) { | ||
89 | continue; | ||
90 | } | ||
91 | $font = substr($font, 1, $length - 2); | ||
92 | } | ||
93 | |||
94 | $font = $this->expandCSSEscape($font); | ||
95 | |||
96 | // $font is a pure representation of the font name | ||
97 | |||
98 | if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) { | ||
99 | continue; | ||
100 | } | ||
101 | |||
102 | if (ctype_alnum($font) && $font !== '') { | ||
103 | // very simple font, allow it in unharmed | ||
104 | $final .= $font . ', '; | ||
105 | continue; | ||
106 | } | ||
107 | |||
108 | // bugger out on whitespace. form feed (0C) really | ||
109 | // shouldn't show up regardless | ||
110 | $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font); | ||
111 | |||
112 | // Here, there are various classes of characters which need | ||
113 | // to be treated differently: | ||
114 | // - Alphanumeric characters are essentially safe. We | ||
115 | // handled these above. | ||
116 | // - Spaces require quoting, though most parsers will do | ||
117 | // the right thing if there aren't any characters that | ||
118 | // can be misinterpreted | ||
119 | // - Dashes rarely occur, but they fairly unproblematic | ||
120 | // for parsing/rendering purposes. | ||
121 | // The above characters cover the majority of Western font | ||
122 | // names. | ||
123 | // - Arbitrary Unicode characters not in ASCII. Because | ||
124 | // most parsers give little thought to Unicode, treatment | ||
125 | // of these codepoints is basically uniform, even for | ||
126 | // punctuation-like codepoints. These characters can | ||
127 | // show up in non-Western pages and are supported by most | ||
128 | // major browsers, for example: "MS 明朝" is a | ||
129 | // legitimate font-name | ||
130 | // <http://ja.wikipedia.org/wiki/MS_明朝>. See | ||
131 | // the CSS3 spec for more examples: | ||
132 | // <http://www.w3.org/TR/2011/WD-css3-fonts-20110324/localizedfamilynames.png> | ||
133 | // You can see live samples of these on the Internet: | ||
134 | // <http://www.google.co.jp/search?q=font-family+MS+明朝|ゴシック> | ||
135 | // However, most of these fonts have ASCII equivalents: | ||
136 | // for example, 'MS Mincho', and it's considered | ||
137 | // professional to use ASCII font names instead of | ||
138 | // Unicode font names. Thanks Takeshi Terada for | ||
139 | // providing this information. | ||
140 | // The following characters, to my knowledge, have not been | ||
141 | // used to name font names. | ||
142 | // - Single quote. While theoretically you might find a | ||
143 | // font name that has a single quote in its name (serving | ||
144 | // as an apostrophe, e.g. Dave's Scribble), I haven't | ||
145 | // been able to find any actual examples of this. | ||
146 | // Internet Explorer's cssText translation (which I | ||
147 | // believe is invoked by innerHTML) normalizes any | ||
148 | // quoting to single quotes, and fails to escape single | ||
149 | // quotes. (Note that this is not IE's behavior for all | ||
150 | // CSS properties, just some sort of special casing for | ||
151 | // font-family). So a single quote *cannot* be used | ||
152 | // safely in the font-family context if there will be an | ||
153 | // innerHTML/cssText translation. Note that Firefox 3.x | ||
154 | // does this too. | ||
155 | // - Double quote. In IE, these get normalized to | ||
156 | // single-quotes, no matter what the encoding. (Fun | ||
157 | // fact, in IE8, the 'content' CSS property gained | ||
158 | // support, where they special cased to preserve encoded | ||
159 | // double quotes, but still translate unadorned double | ||
160 | // quotes into single quotes.) So, because their | ||
161 | // fixpoint behavior is identical to single quotes, they | ||
162 | // cannot be allowed either. Firefox 3.x displays | ||
163 | // single-quote style behavior. | ||
164 | // - Backslashes are reduced by one (so \\ -> \) every | ||
165 | // iteration, so they cannot be used safely. This shows | ||
166 | // up in IE7, IE8 and FF3 | ||
167 | // - Semicolons, commas and backticks are handled properly. | ||
168 | // - The rest of the ASCII punctuation is handled properly. | ||
169 | // We haven't checked what browsers do to unadorned | ||
170 | // versions, but this is not important as long as the | ||
171 | // browser doesn't /remove/ surrounding quotes (as IE does | ||
172 | // for HTML). | ||
173 | // | ||
174 | // With these results in hand, we conclude that there are | ||
175 | // various levels of safety: | ||
176 | // - Paranoid: alphanumeric, spaces and dashes(?) | ||
177 | // - International: Paranoid + non-ASCII Unicode | ||
178 | // - Edgy: Everything except quotes, backslashes | ||
179 | // - NoJS: Standards compliance, e.g. sod IE. Note that | ||
180 | // with some judicious character escaping (since certain | ||
181 | // types of escaping doesn't work) this is theoretically | ||
182 | // OK as long as innerHTML/cssText is not called. | ||
183 | // We believe that international is a reasonable default | ||
184 | // (that we will implement now), and once we do more | ||
185 | // extensive research, we may feel comfortable with dropping | ||
186 | // it down to edgy. | ||
187 | |||
188 | // Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of | ||
189 | // str(c)spn assumes that the string was already well formed | ||
190 | // Unicode (which of course it is). | ||
191 | if (strspn($font, $this->mask) !== strlen($font)) { | ||
192 | continue; | ||
193 | } | ||
194 | |||
195 | // Historical: | ||
196 | // In the absence of innerHTML/cssText, these ugly | ||
197 | // transforms don't pose a security risk (as \\ and \" | ||
198 | // might--these escapes are not supported by most browsers). | ||
199 | // We could try to be clever and use single-quote wrapping | ||
200 | // when there is a double quote present, but I have choosen | ||
201 | // not to implement that. (NOTE: you can reduce the amount | ||
202 | // of escapes by one depending on what quoting style you use) | ||
203 | // $font = str_replace('\\', '\\5C ', $font); | ||
204 | // $font = str_replace('"', '\\22 ', $font); | ||
205 | // $font = str_replace("'", '\\27 ', $font); | ||
206 | |||
207 | // font possibly with spaces, requires quoting | ||
208 | $final .= "'$font', "; | ||
209 | } | ||
210 | $final = rtrim($final, ', '); | ||
211 | if ($final === '') { | ||
212 | return false; | ||
213 | } | ||
214 | return $final; | ||
215 | } | ||
216 | |||
217 | } | ||
218 | |||
219 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ident.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ident.php new file mode 100644 index 00000000..5f13edfd --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ident.php | |||
@@ -0,0 +1,32 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates based on {ident} CSS grammar production | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * @param string $string | ||
11 | * @param HTMLPurifier_Config $config | ||
12 | * @param HTMLPurifier_Context $context | ||
13 | * @return bool|string | ||
14 | */ | ||
15 | public function validate($string, $config, $context) | ||
16 | { | ||
17 | $string = trim($string); | ||
18 | |||
19 | // early abort: '' and '0' (strings that convert to false) are invalid | ||
20 | if (!$string) { | ||
21 | return false; | ||
22 | } | ||
23 | |||
24 | $pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/'; | ||
25 | if (!preg_match($pattern, $string)) { | ||
26 | return false; | ||
27 | } | ||
28 | return $string; | ||
29 | } | ||
30 | } | ||
31 | |||
32 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php new file mode 100644 index 00000000..f4848494 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php | |||
@@ -0,0 +1,56 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Decorator which enables !important to be used in CSS values. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | /** | ||
9 | * @type HTMLPurifier_AttrDef | ||
10 | */ | ||
11 | public $def; | ||
12 | /** | ||
13 | * @type bool | ||
14 | */ | ||
15 | public $allow; | ||
16 | |||
17 | /** | ||
18 | * @param HTMLPurifier_AttrDef $def Definition to wrap | ||
19 | * @param bool $allow Whether or not to allow !important | ||
20 | */ | ||
21 | public function __construct($def, $allow = false) | ||
22 | { | ||
23 | $this->def = $def; | ||
24 | $this->allow = $allow; | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * Intercepts and removes !important if necessary | ||
29 | * @param string $string | ||
30 | * @param HTMLPurifier_Config $config | ||
31 | * @param HTMLPurifier_Context $context | ||
32 | * @return bool|string | ||
33 | */ | ||
34 | public function validate($string, $config, $context) | ||
35 | { | ||
36 | // test for ! and important tokens | ||
37 | $string = trim($string); | ||
38 | $is_important = false; | ||
39 | // :TODO: optimization: test directly for !important and ! important | ||
40 | if (strlen($string) >= 9 && substr($string, -9) === 'important') { | ||
41 | $temp = rtrim(substr($string, 0, -9)); | ||
42 | // use a temp, because we might want to restore important | ||
43 | if (strlen($temp) >= 1 && substr($temp, -1) === '!') { | ||
44 | $string = rtrim(substr($temp, 0, -1)); | ||
45 | $is_important = true; | ||
46 | } | ||
47 | } | ||
48 | $string = $this->def->validate($string, $config, $context); | ||
49 | if ($this->allow && $is_important) { | ||
50 | $string .= ' !important'; | ||
51 | } | ||
52 | return $string; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Length.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Length.php new file mode 100644 index 00000000..88da41d9 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Length.php | |||
@@ -0,0 +1,77 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Represents a Length as defined by CSS. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * @type HTMLPurifier_Length|string | ||
11 | */ | ||
12 | protected $min; | ||
13 | |||
14 | /** | ||
15 | * @type HTMLPurifier_Length|string | ||
16 | */ | ||
17 | protected $max; | ||
18 | |||
19 | /** | ||
20 | * @param HTMLPurifier_Length|string $min Minimum length, or null for no bound. String is also acceptable. | ||
21 | * @param HTMLPurifier_Length|string $max Maximum length, or null for no bound. String is also acceptable. | ||
22 | */ | ||
23 | public function __construct($min = null, $max = null) | ||
24 | { | ||
25 | $this->min = $min !== null ? HTMLPurifier_Length::make($min) : null; | ||
26 | $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * @param string $string | ||
31 | * @param HTMLPurifier_Config $config | ||
32 | * @param HTMLPurifier_Context $context | ||
33 | * @return bool|string | ||
34 | */ | ||
35 | public function validate($string, $config, $context) | ||
36 | { | ||
37 | $string = $this->parseCDATA($string); | ||
38 | |||
39 | // Optimizations | ||
40 | if ($string === '') { | ||
41 | return false; | ||
42 | } | ||
43 | if ($string === '0') { | ||
44 | return '0'; | ||
45 | } | ||
46 | if (strlen($string) === 1) { | ||
47 | return false; | ||
48 | } | ||
49 | |||
50 | $length = HTMLPurifier_Length::make($string); | ||
51 | if (!$length->isValid()) { | ||
52 | return false; | ||
53 | } | ||
54 | |||
55 | if ($this->min) { | ||
56 | $c = $length->compareTo($this->min); | ||
57 | if ($c === false) { | ||
58 | return false; | ||
59 | } | ||
60 | if ($c < 0) { | ||
61 | return false; | ||
62 | } | ||
63 | } | ||
64 | if ($this->max) { | ||
65 | $c = $length->compareTo($this->max); | ||
66 | if ($c === false) { | ||
67 | return false; | ||
68 | } | ||
69 | if ($c > 0) { | ||
70 | return false; | ||
71 | } | ||
72 | } | ||
73 | return $length->toString(); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php new file mode 100644 index 00000000..b4cce9a9 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/ListStyle.php | |||
@@ -0,0 +1,112 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates shorthand CSS property list-style. | ||
5 | * @warning Does not support url tokens that have internal spaces. | ||
6 | */ | ||
7 | class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef | ||
8 | { | ||
9 | |||
10 | /** | ||
11 | * Local copy of validators. | ||
12 | * @type HTMLPurifier_AttrDef[] | ||
13 | * @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl. | ||
14 | */ | ||
15 | protected $info; | ||
16 | |||
17 | /** | ||
18 | * @param HTMLPurifier_Config $config | ||
19 | */ | ||
20 | public function __construct($config) | ||
21 | { | ||
22 | $def = $config->getCSSDefinition(); | ||
23 | $this->info['list-style-type'] = $def->info['list-style-type']; | ||
24 | $this->info['list-style-position'] = $def->info['list-style-position']; | ||
25 | $this->info['list-style-image'] = $def->info['list-style-image']; | ||
26 | } | ||
27 | |||
28 | /** | ||
29 | * @param string $string | ||
30 | * @param HTMLPurifier_Config $config | ||
31 | * @param HTMLPurifier_Context $context | ||
32 | * @return bool|string | ||
33 | */ | ||
34 | public function validate($string, $config, $context) | ||
35 | { | ||
36 | // regular pre-processing | ||
37 | $string = $this->parseCDATA($string); | ||
38 | if ($string === '') { | ||
39 | return false; | ||
40 | } | ||
41 | |||
42 | // assumes URI doesn't have spaces in it | ||
43 | $bits = explode(' ', strtolower($string)); // bits to process | ||
44 | |||
45 | $caught = array(); | ||
46 | $caught['type'] = false; | ||
47 | $caught['position'] = false; | ||
48 | $caught['image'] = false; | ||
49 | |||
50 | $i = 0; // number of catches | ||
51 | $none = false; | ||
52 | |||
53 | foreach ($bits as $bit) { | ||
54 | if ($i >= 3) { | ||
55 | return; | ||
56 | } // optimization bit | ||
57 | if ($bit === '') { | ||
58 | continue; | ||
59 | } | ||
60 | foreach ($caught as $key => $status) { | ||
61 | if ($status !== false) { | ||
62 | continue; | ||
63 | } | ||
64 | $r = $this->info['list-style-' . $key]->validate($bit, $config, $context); | ||
65 | if ($r === false) { | ||
66 | continue; | ||
67 | } | ||
68 | if ($r === 'none') { | ||
69 | if ($none) { | ||
70 | continue; | ||
71 | } else { | ||
72 | $none = true; | ||
73 | } | ||
74 | if ($key == 'image') { | ||
75 | continue; | ||
76 | } | ||
77 | } | ||
78 | $caught[$key] = $r; | ||
79 | $i++; | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | if (!$i) { | ||
85 | return false; | ||
86 | } | ||
87 | |||
88 | $ret = array(); | ||
89 | |||
90 | // construct type | ||
91 | if ($caught['type']) { | ||
92 | $ret[] = $caught['type']; | ||
93 | } | ||
94 | |||
95 | // construct image | ||
96 | if ($caught['image']) { | ||
97 | $ret[] = $caught['image']; | ||
98 | } | ||
99 | |||
100 | // construct position | ||
101 | if ($caught['position']) { | ||
102 | $ret[] = $caught['position']; | ||
103 | } | ||
104 | |||
105 | if (empty($ret)) { | ||
106 | return false; | ||
107 | } | ||
108 | return implode(' ', $ret); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Multiple.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Multiple.php new file mode 100644 index 00000000..73d586f2 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Multiple.php | |||
@@ -0,0 +1,71 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Framework class for strings that involve multiple values. | ||
5 | * | ||
6 | * Certain CSS properties such as border-width and margin allow multiple | ||
7 | * lengths to be specified. This class can take a vanilla border-width | ||
8 | * definition and multiply it, usually into a max of four. | ||
9 | * | ||
10 | * @note Even though the CSS specification isn't clear about it, inherit | ||
11 | * can only be used alone: it will never manifest as part of a multi | ||
12 | * shorthand declaration. Thus, this class does not allow inherit. | ||
13 | */ | ||
14 | class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef | ||
15 | { | ||
16 | /** | ||
17 | * Instance of component definition to defer validation to. | ||
18 | * @type HTMLPurifier_AttrDef | ||
19 | * @todo Make protected | ||
20 | */ | ||
21 | public $single; | ||
22 | |||
23 | /** | ||
24 | * Max number of values allowed. | ||
25 | * @todo Make protected | ||
26 | */ | ||
27 | public $max; | ||
28 | |||
29 | /** | ||
30 | * @param HTMLPurifier_AttrDef $single HTMLPurifier_AttrDef to multiply | ||
31 | * @param int $max Max number of values allowed (usually four) | ||
32 | */ | ||
33 | public function __construct($single, $max = 4) | ||
34 | { | ||
35 | $this->single = $single; | ||
36 | $this->max = $max; | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * @param string $string | ||
41 | * @param HTMLPurifier_Config $config | ||
42 | * @param HTMLPurifier_Context $context | ||
43 | * @return bool|string | ||
44 | */ | ||
45 | public function validate($string, $config, $context) | ||
46 | { | ||
47 | $string = $this->parseCDATA($string); | ||
48 | if ($string === '') { | ||
49 | return false; | ||
50 | } | ||
51 | $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n | ||
52 | $length = count($parts); | ||
53 | $final = ''; | ||
54 | for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) { | ||
55 | if (ctype_space($parts[$i])) { | ||
56 | continue; | ||
57 | } | ||
58 | $result = $this->single->validate($parts[$i], $config, $context); | ||
59 | if ($result !== false) { | ||
60 | $final .= $result . ' '; | ||
61 | $num++; | ||
62 | } | ||
63 | } | ||
64 | if ($final === '') { | ||
65 | return false; | ||
66 | } | ||
67 | return rtrim($final); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Number.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Number.php new file mode 100644 index 00000000..c78f6c9d --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Number.php | |||
@@ -0,0 +1,84 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a number as defined by the CSS spec. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * Indicates whether or not only positive values are allowed. | ||
11 | * @type bool | ||
12 | */ | ||
13 | protected $non_negative = false; | ||
14 | |||
15 | /** | ||
16 | * @param bool $non_negative indicates whether negatives are forbidden | ||
17 | */ | ||
18 | public function __construct($non_negative = false) | ||
19 | { | ||
20 | $this->non_negative = $non_negative; | ||
21 | } | ||
22 | |||
23 | /** | ||
24 | * @param string $number | ||
25 | * @param HTMLPurifier_Config $config | ||
26 | * @param HTMLPurifier_Context $context | ||
27 | * @return string|bool | ||
28 | * @warning Some contexts do not pass $config, $context. These | ||
29 | * variables should not be used without checking HTMLPurifier_Length | ||
30 | */ | ||
31 | public function validate($number, $config, $context) | ||
32 | { | ||
33 | $number = $this->parseCDATA($number); | ||
34 | |||
35 | if ($number === '') { | ||
36 | return false; | ||
37 | } | ||
38 | if ($number === '0') { | ||
39 | return '0'; | ||
40 | } | ||
41 | |||
42 | $sign = ''; | ||
43 | switch ($number[0]) { | ||
44 | case '-': | ||
45 | if ($this->non_negative) { | ||
46 | return false; | ||
47 | } | ||
48 | $sign = '-'; | ||
49 | case '+': | ||
50 | $number = substr($number, 1); | ||
51 | } | ||
52 | |||
53 | if (ctype_digit($number)) { | ||
54 | $number = ltrim($number, '0'); | ||
55 | return $number ? $sign . $number : '0'; | ||
56 | } | ||
57 | |||
58 | // Period is the only non-numeric character allowed | ||
59 | if (strpos($number, '.') === false) { | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | list($left, $right) = explode('.', $number, 2); | ||
64 | |||
65 | if ($left === '' && $right === '') { | ||
66 | return false; | ||
67 | } | ||
68 | if ($left !== '' && !ctype_digit($left)) { | ||
69 | return false; | ||
70 | } | ||
71 | |||
72 | $left = ltrim($left, '0'); | ||
73 | $right = rtrim($right, '0'); | ||
74 | |||
75 | if ($right === '') { | ||
76 | return $left ? $sign . $left : '0'; | ||
77 | } elseif (!ctype_digit($right)) { | ||
78 | return false; | ||
79 | } | ||
80 | return $sign . $left . '.' . $right; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Percentage.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Percentage.php new file mode 100644 index 00000000..aac1a6f5 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/Percentage.php | |||
@@ -0,0 +1,54 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a Percentage as defined by the CSS spec. | ||
5 | */ | ||
6 | class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef | ||
7 | { | ||
8 | |||
9 | /** | ||
10 | * Instance to defer number validation to. | ||
11 | * @type HTMLPurifier_AttrDef_CSS_Number | ||
12 | */ | ||
13 | protected $number_def; | ||
14 | |||
15 | /** | ||
16 | * @param bool $non_negative Whether to forbid negative values | ||
17 | */ | ||
18 | public function __construct($non_negative = false) | ||
19 | { | ||
20 | $this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); | ||
21 | } | ||
22 | |||
23 | /** | ||
24 | * @param string $string | ||
25 | * @param HTMLPurifier_Config $config | ||
26 | * @param HTMLPurifier_Context $context | ||
27 | * @return bool|string | ||
28 | */ | ||
29 | public function validate($string, $config, $context) | ||
30 | { | ||
31 | $string = $this->parseCDATA($string); | ||
32 | |||
33 | if ($string === '') { | ||
34 | return false; | ||
35 | } | ||
36 | $length = strlen($string); | ||
37 | if ($length === 1) { | ||
38 | return false; | ||
39 | } | ||
40 | if ($string[$length - 1] !== '%') { | ||
41 | return false; | ||
42 | } | ||
43 | |||
44 | $number = substr($string, 0, $length - 1); | ||
45 | $number = $this->number_def->validate($number, $config, $context); | ||
46 | |||
47 | if ($number === false) { | ||
48 | return false; | ||
49 | } | ||
50 | return "$number%"; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php new file mode 100644 index 00000000..3992de0e --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/TextDecoration.php | |||
@@ -0,0 +1,46 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates the value for the CSS property text-decoration | ||
5 | * @note This class could be generalized into a version that acts sort of | ||
6 | * like Enum except you can compound the allowed values. | ||
7 | */ | ||
8 | class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef | ||
9 | { | ||
10 | |||
11 | /** | ||
12 | * @param string $string | ||
13 | * @param HTMLPurifier_Config $config | ||
14 | * @param HTMLPurifier_Context $context | ||
15 | * @return bool|string | ||
16 | */ | ||
17 | public function validate($string, $config, $context) | ||
18 | { | ||
19 | static $allowed_values = array( | ||
20 | 'line-through' => true, | ||
21 | 'overline' => true, | ||
22 | 'underline' => true, | ||
23 | ); | ||
24 | |||
25 | $string = strtolower($this->parseCDATA($string)); | ||
26 | |||
27 | if ($string === 'none') { | ||
28 | return $string; | ||
29 | } | ||
30 | |||
31 | $parts = explode(' ', $string); | ||
32 | $final = ''; | ||
33 | foreach ($parts as $part) { | ||
34 | if (isset($allowed_values[$part])) { | ||
35 | $final .= $part . ' '; | ||
36 | } | ||
37 | } | ||
38 | $final = rtrim($final); | ||
39 | if ($final === '') { | ||
40 | return false; | ||
41 | } | ||
42 | return $final; | ||
43 | } | ||
44 | } | ||
45 | |||
46 | // vim: et sw=4 sts=4 | ||
diff --git a/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/URI.php b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/URI.php new file mode 100644 index 00000000..482b0997 --- /dev/null +++ b/inc/3rdparty/htmlpurifier/HTMLPurifier/AttrDef/CSS/URI.php | |||
@@ -0,0 +1,74 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Validates a URI in CSS syntax, which uses url('http://example.com') | ||
5 | * @note While theoretically speaking a URI in a CSS document could | ||
6 | * be non-embedded, as of CSS2 there is no such usage so we're | ||
7 | * generalizing it. This may need to be changed in the future. | ||
8 | * @warning Since HTMLPurifier_AttrDef_CSS blindly uses semicolons as | ||
9 | * the separator, you cannot put a literal semicolon in | ||
10 | * in the URI. Try percent encoding it, in that case. | ||
11 | */ | ||
12 | class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI | ||
13 | { | ||
14 | |||
15 | public function __construct() | ||
16 | { | ||
17 | parent::__construct(true); // always embedded | ||
18 | } | ||
19 | |||
20 | /** | ||
21 | * @param string $uri_string | ||
22 | * @param HTMLPurifier_Config $config | ||
23 | * @param HTMLPurifier_Context $context | ||
24 | * @return bool|string | ||
25 | */ | ||
26 | public function validate($uri_string, $config, $context) | ||
27 | { | ||
28 | // parse the URI out of the string and then pass it onto | ||
29 | // the parent object | ||
30 | |||
31 | $uri_string = $this->parseCDATA($uri_string); | ||
32 | if (strpos($uri_string, 'url(') !== 0) { | ||
33 | return false; | ||
34 | } | ||
35 | $uri_string = substr($uri_string, 4); | ||
36 | $new_length = strlen($uri_string) - 1; | ||
37 | if ($uri_string[$new_length] != ')') { | ||
38 | return false; | ||
39 | } | ||
40 | $uri = trim(substr($uri_string, 0, $new_length)); | ||
41 | |||
42 | if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) { | ||
43 | $quote = $uri[0]; | ||
44 | $new_length = strlen($uri) - 1; | ||
45 | if ($uri[$new_length] !== $quote) { | ||
46 | return false; | ||
47 | } | ||
48 | $uri = substr($uri, 1, $new_length - 1); | ||
49 | } | ||
50 | |||
51 | $uri = $this->expandCSSEscape($uri); | ||
52 | |||
53 | $result = parent::validate($uri, $config, $context); | ||
54 | |||
55 | if ($result === false) { | ||
56 | return false; | ||
57 | } | ||
58 | |||
59 | // extra sanity check; should have been done by URI | ||
60 | $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result); | ||
61 | |||
62 | // suspicious characters are ()'; we're going to percent encode | ||
63 | // them for safety. | ||
64 | $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result); | ||
65 | |||
66 | // there's an extra bug where ampersands lose their escaping on | ||
67 | // an innerHTML cycle, so a very unlucky query parameter could | ||
68 | // then change the meaning of the URL. Unfortunately, there's | ||
69 | // not much we can do about that... | ||
70 | return "url(\"$result\")"; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | // vim: et sw=4 sts=4 | ||