Safe SVG - Version 1.6.0

Version Description

  • Fairly big new feature - The library now allows <use> elements as long as they don't reference external files!
  • You can now also embed safe image types within the SVG and not have them stripped (PNG, GIF, JPG)
Download this release

Release Info

Developer enshrined
Plugin Icon 128x128 Safe SVG
Version 1.6.0
Comparing to
See all releases

Code changes from version 1.5.3 to 1.6.0

lib/composer.lock CHANGED
@@ -9,16 +9,16 @@
9
  "packages": [
10
  {
11
  "name": "enshrined/svg-sanitize",
12
- "version": "0.7.0",
13
  "source": {
14
  "type": "git",
15
  "url": "https://github.com/darylldoyle/svg-sanitizer.git",
16
- "reference": "0bdbbd15b9ca501c33c9373968922d055e7064db"
17
  },
18
  "dist": {
19
  "type": "zip",
20
- "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0bdbbd15b9ca501c33c9373968922d055e7064db",
21
- "reference": "0bdbbd15b9ca501c33c9373968922d055e7064db",
22
  "shasum": ""
23
  },
24
  "require-dev": {
@@ -42,7 +42,7 @@
42
  }
43
  ],
44
  "description": "An SVG sanitizer for PHP",
45
- "time": "2017-06-20 16:13:01"
46
  }
47
  ],
48
  "packages-dev": [],
9
  "packages": [
10
  {
11
  "name": "enshrined/svg-sanitize",
12
+ "version": "0.8.2",
13
  "source": {
14
  "type": "git",
15
  "url": "https://github.com/darylldoyle/svg-sanitizer.git",
16
+ "reference": "432fc4fc7e95b8a866790ba27e35076b9dd96ebe"
17
  },
18
  "dist": {
19
  "type": "zip",
20
+ "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/432fc4fc7e95b8a866790ba27e35076b9dd96ebe",
21
+ "reference": "432fc4fc7e95b8a866790ba27e35076b9dd96ebe",
22
  "shasum": ""
23
  },
24
  "require-dev": {
42
  }
43
  ],
44
  "description": "An SVG sanitizer for PHP",
45
+ "time": "2017-12-06 15:31:26"
46
  }
47
  ],
48
  "packages-dev": [],
lib/vendor/composer/installed.json CHANGED
@@ -1,24 +1,24 @@
1
  [
2
  {
3
  "name": "enshrined/svg-sanitize",
4
- "version": "0.7.0",
5
- "version_normalized": "0.7.0.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/darylldoyle/svg-sanitizer.git",
9
- "reference": "0bdbbd15b9ca501c33c9373968922d055e7064db"
10
  },
11
  "dist": {
12
  "type": "zip",
13
- "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0bdbbd15b9ca501c33c9373968922d055e7064db",
14
- "reference": "0bdbbd15b9ca501c33c9373968922d055e7064db",
15
  "shasum": ""
16
  },
17
  "require-dev": {
18
  "codeclimate/php-test-reporter": "^0.1.2",
19
  "phpunit/phpunit": "^4.7"
20
  },
21
- "time": "2017-06-20 16:13:01",
22
  "type": "library",
23
  "installation-source": "dist",
24
  "autoload": {
1
  [
2
  {
3
  "name": "enshrined/svg-sanitize",
4
+ "version": "0.8.2",
5
+ "version_normalized": "0.8.2.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/darylldoyle/svg-sanitizer.git",
9
+ "reference": "432fc4fc7e95b8a866790ba27e35076b9dd96ebe"
10
  },
11
  "dist": {
12
  "type": "zip",
13
+ "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/432fc4fc7e95b8a866790ba27e35076b9dd96ebe",
14
+ "reference": "432fc4fc7e95b8a866790ba27e35076b9dd96ebe",
15
  "shasum": ""
16
  },
17
  "require-dev": {
18
  "codeclimate/php-test-reporter": "^0.1.2",
19
  "phpunit/phpunit": "^4.7"
20
  },
21
+ "time": "2017-12-06 15:31:26",
22
  "type": "library",
23
  "installation-source": "dist",
24
  "autoload": {
lib/vendor/enshrined/svg-sanitize/.travis.yml CHANGED
@@ -1,10 +1,10 @@
1
  language: php
2
  php:
3
- - 5.3
4
  - 5.4
5
  - 5.5
6
  - 5.6
7
  - 7.0
 
8
 
9
  before_script:
10
  - composer install --dev
1
  language: php
2
  php:
 
3
  - 5.4
4
  - 5.5
5
  - 5.6
6
  - 7.0
7
+ - 7.1
8
 
9
  before_script:
10
  - composer install --dev
lib/vendor/enshrined/svg-sanitize/src/Sanitizer.php CHANGED
@@ -23,11 +23,6 @@ class Sanitizer
23
  */
24
  const SCRIPT_REGEX = '/(?:\w+script|data):/xi';
25
 
26
- /**
27
- * Regex to test for remote URLs in linked assets
28
- */
29
- const REMOTE_REFERENCE_REGEX = '/url\(([\'"]?(?:http|https):)[\'"]?([^\'"\)]*)[\'"]?\)/xi';
30
-
31
  /**
32
  * @var DOMDocument
33
  */
@@ -58,6 +53,11 @@ class Sanitizer
58
  */
59
  protected $removeRemoteReferences = false;
60
 
 
 
 
 
 
61
  /**
62
  *
63
  */
@@ -171,7 +171,11 @@ class Sanitizer
171
  $this->startClean($allElements);
172
 
173
  // Save cleaned XML to a variable
174
- $clean = $this->xmlDocument->saveXML($this->xmlDocument, LIBXML_NOEMPTYTAG);
 
 
 
 
175
 
176
  $this->resetAfter();
177
 
@@ -245,6 +249,13 @@ class Sanitizer
245
  $this->cleanXlinkHrefs($currentElement);
246
 
247
  $this->cleanHrefs($currentElement);
 
 
 
 
 
 
 
248
  }
249
  }
250
 
@@ -283,7 +294,15 @@ class Sanitizer
283
  {
284
  $xlinks = $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
285
  if (preg_match(self::SCRIPT_REGEX, $xlinks) === 1) {
286
- $element->removeAttributeNS('http://www.w3.org/1999/xlink', 'href');
 
 
 
 
 
 
 
 
287
  }
288
  }
289
 
@@ -300,15 +319,34 @@ class Sanitizer
300
  }
301
  }
302
 
 
 
 
 
 
 
 
 
 
 
 
303
  /**
304
  * Does this attribute value have a remote reference?
305
  *
306
  * @param $value
307
  * @return bool
308
  */
309
- protected function hasRemoteReference($value)
310
- {
311
- if (preg_match(self::REMOTE_REFERENCE_REGEX, $value) === 1) {
 
 
 
 
 
 
 
 
312
  return true;
313
  }
314
 
@@ -326,7 +364,17 @@ class Sanitizer
326
  }
327
 
328
  /**
329
- * Check to see if an attribure is an aria attribute or not
 
 
 
 
 
 
 
 
 
 
330
  *
331
  * @param $attributeName
332
  *
@@ -344,7 +392,7 @@ class Sanitizer
344
  }
345
 
346
  /**
347
- * Check to see if an attribure is an data attribute or not
348
  *
349
  * @param $attributeName
350
  *
@@ -360,4 +408,19 @@ class Sanitizer
360
 
361
  return false;
362
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  }
23
  */
24
  const SCRIPT_REGEX = '/(?:\w+script|data):/xi';
25
 
 
 
 
 
 
26
  /**
27
  * @var DOMDocument
28
  */
53
  */
54
  protected $removeRemoteReferences = false;
55
 
56
+ /**
57
+ * @var bool
58
+ */
59
+ protected $removeXMLTag = false;
60
+
61
  /**
62
  *
63
  */
171
  $this->startClean($allElements);
172
 
173
  // Save cleaned XML to a variable
174
+ if($this->removeXMLTag) {
175
+ $clean = $this->xmlDocument->saveXML($this->xmlDocument->documentElement, LIBXML_NOEMPTYTAG);
176
+ } else {
177
+ $clean = $this->xmlDocument->saveXML($this->xmlDocument, LIBXML_NOEMPTYTAG);
178
+ }
179
 
180
  $this->resetAfter();
181
 
249
  $this->cleanXlinkHrefs($currentElement);
250
 
251
  $this->cleanHrefs($currentElement);
252
+
253
+ if(strtolower($currentElement->tagName) === 'use') {
254
+ if($this->isUseTagDirty($currentElement)) {
255
+ $currentElement->parentNode->removeChild($currentElement);
256
+ continue;
257
+ }
258
+ }
259
  }
260
  }
261
 
294
  {
295
  $xlinks = $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
296
  if (preg_match(self::SCRIPT_REGEX, $xlinks) === 1) {
297
+ if(! in_array(substr($xlinks, 0, 14), array(
298
+ 'data:image/png', // PNG
299
+ 'data:image/gif', // GIF
300
+ 'data:image/jpg', // JPG
301
+ 'data:image/jpe', // JPEG
302
+ 'data:image/pjp', // PJPEG
303
+ ))) {
304
+ $element->removeAttributeNS( 'http://www.w3.org/1999/xlink', 'href' );
305
+ }
306
  }
307
  }
308
 
319
  }
320
  }
321
 
322
+ /**
323
+ * Removes non-printable ASCII characters from string & trims it
324
+ *
325
+ * @param string $value
326
+ * @return bool
327
+ */
328
+ protected function removeNonPrintableCharacters($value)
329
+ {
330
+ return trim(preg_replace('/[^ -~]/xu','',$value));
331
+ }
332
+
333
  /**
334
  * Does this attribute value have a remote reference?
335
  *
336
  * @param $value
337
  * @return bool
338
  */
339
+ protected function hasRemoteReference($value){
340
+ $value = $this->removeNonPrintableCharacters($value);
341
+
342
+ $wrapped_in_url = preg_match('~^url\(\s*[\'"]\s*(.*)\s*[\'"]\s*\)$~xi', $value, $match);
343
+ if (!$wrapped_in_url){
344
+ return false;
345
+ }
346
+
347
+ $value = trim($match[1], '\'"');
348
+
349
+ if (preg_match('~^((https?|ftp|file):)?//~xi', $value)){
350
  return true;
351
  }
352
 
364
  }
365
 
366
  /**
367
+ * Should we remove the XML tag in the header?
368
+ *
369
+ * @param bool $removeXMLTag
370
+ */
371
+ public function removeXMLTag ($removeXMLTag = false)
372
+ {
373
+ $this->removeXMLTag = (bool) $removeXMLTag;
374
+ }
375
+
376
+ /**
377
+ * Check to see if an attribute is an aria attribute or not
378
  *
379
  * @param $attributeName
380
  *
392
  }
393
 
394
  /**
395
+ * Check to see if an attribute is an data attribute or not
396
  *
397
  * @param $attributeName
398
  *
408
 
409
  return false;
410
  }
411
+
412
+ /**
413
+ * Make sure our use tag is only referencing internal resources
414
+ *
415
+ * @param \DOMElement $element
416
+ * @return bool
417
+ */
418
+ protected function isUseTagDirty(\DOMElement $element) {
419
+ $xlinks = $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
420
+ if ($xlinks && substr($xlinks, 0, 1) !== '#') {
421
+ return true;
422
+ }
423
+
424
+ return false;
425
+ }
426
  }
lib/vendor/enshrined/svg-sanitize/src/data/AllowedTags.php CHANGED
@@ -27,7 +27,7 @@ class AllowedTags implements TagInterface
27
  'datalist','dd','decorator','del','details','dfn','dir','div','dl','dt',
28
  'element','em','fieldset','figcaption','figure','font','footer','form',
29
  'h1','h2','h3','h4','h5','h6','head','header','hgroup','hr','html','i',
30
- 'img','input','ins','kbd','label','legend','li','main','map','mark',
31
  'marquee','menu','menuitem','meter','nav','nobr','ol','optgroup',
32
  'option','output','p','pre','progress','q','rp','rt','ruby','s','samp',
33
  'section','select','shadow','small','source','spacer','span','strike',
@@ -41,7 +41,7 @@ class AllowedTags implements TagInterface
41
  'ellipse','filter','font','g','glyph','glyphref','hkern','image','line',
42
  'lineargradient','marker','mask','metadata','mpath','path','pattern',
43
  'polygon','polyline','radialgradient','rect','stop','switch','symbol',
44
- 'text','textpath','title','tref','tspan','view','vkern',
45
 
46
  // SVG Filters
47
  'feblend','fecolormatrix','fecomponenttransfer','fecomposite',
27
  'datalist','dd','decorator','del','details','dfn','dir','div','dl','dt',
28
  'element','em','fieldset','figcaption','figure','font','footer','form',
29
  'h1','h2','h3','h4','h5','h6','head','header','hgroup','hr','html','i',
30
+ 'image','img','input','ins','kbd','label','legend','li','main','map','mark',
31
  'marquee','menu','menuitem','meter','nav','nobr','ol','optgroup',
32
  'option','output','p','pre','progress','q','rp','rt','ruby','s','samp',
33
  'section','select','shadow','small','source','spacer','span','strike',
41
  'ellipse','filter','font','g','glyph','glyphref','hkern','image','line',
42
  'lineargradient','marker','mask','metadata','mpath','path','pattern',
43
  'polygon','polyline','radialgradient','rect','stop','switch','symbol',
44
+ 'text','textpath','title','tref','tspan','view','vkern', 'use',
45
 
46
  // SVG Filters
47
  'feblend','fecolormatrix','fecomponenttransfer','fecomposite',
lib/vendor/enshrined/svg-sanitize/tests/SanitizerTest.php CHANGED
@@ -163,4 +163,19 @@ class SanitizerTest extends PHPUnit_Framework_TestCase
163
 
164
  $this->assertXmlStringEqualsXmlString($expected, $cleanData);
165
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  }
163
 
164
  $this->assertXmlStringEqualsXmlString($expected, $cleanData);
165
  }
166
+
167
+ /**
168
+ * Test that ARIA and Data Attributes are allowed
169
+ */
170
+ public function testThatExternalUseElementsAreStripped()
171
+ {
172
+ $initialData = file_get_contents('tests/data/useTest.svg');
173
+ $expected = file_get_contents('tests/data/useClean.svg');
174
+
175
+ $this->class->minify(false);
176
+ $cleanData = $this->class->sanitize($initialData);
177
+ $this->class->minify(false);
178
+
179
+ $this->assertXmlStringEqualsXmlString($expected, $cleanData);
180
+ }
181
  }
lib/vendor/enshrined/svg-sanitize/tests/data/externalClean.svg CHANGED
@@ -2,6 +2,9 @@
2
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve">
3
  <rect x="0" y="0" width="1000" height="1000"></rect>
4
  <rect x="0" y="0" width="1000" height="1000"></rect>
 
 
 
5
  <rect fill="url('/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
6
  <rect fill="url('#benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
7
- </svg>
2
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve">
3
  <rect x="0" y="0" width="1000" height="1000"></rect>
4
  <rect x="0" y="0" width="1000" height="1000"></rect>
5
+ <rect x="0" y="0" width="1000" height="1000"></rect>
6
+ <rect x="0" y="0" width="1000" height="1000"></rect>
7
+ <rect x="0" y="0" width="1000" height="1000"></rect>
8
  <rect fill="url('/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
9
  <rect fill="url('#benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
10
+ </svg>
lib/vendor/enshrined/svg-sanitize/tests/data/externalTest.svg CHANGED
@@ -3,6 +3,9 @@
3
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve">
4
  <rect fill="url('http://example.com/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
5
  <rect fill="url('https://example.com/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
 
 
 
6
  <rect fill="url('/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
7
  <rect fill="url('#benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
8
- </svg>
3
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve">
4
  <rect fill="url('http://example.com/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
5
  <rect fill="url('https://example.com/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
6
+ <rect fill=" url( ' https://example.com/benis.svg ' ) " x="0" y="0" width="1000" height="1000"></rect>
7
+ <rect fill="url('ftp://192.168.2.1/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
8
+ <rect fill="url('//example.com/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
9
  <rect fill="url('/benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
10
  <rect fill="url('#benis.svg')" x="0" y="0" width="1000" height="1000"></rect>
11
+ </svg>
lib/vendor/enshrined/svg-sanitize/tests/data/useClean.svg ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 68 65">
2
+ <use xlink:href="#a" x="28" fill="#1A374D"/>
3
+ <path id="a" d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-4 0-7-3-7-7s3-7 7-7 7 3 7 7-3 7-7 7z"/>
4
+ </svg>
lib/vendor/enshrined/svg-sanitize/tests/data/useTest.svg ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 68 65">
2
+ <use xlink:href="#a" x="28" fill="#1A374D"/>
3
+ <path id="a" d="M14 27v-20c0-3.7-3.3-7-7-7s-7 3.3-7 7v41c0 8.2 9.2 17 20 17s20-9.2 20-20c0-13.3-13.4-21.8-26-18zm6 25c-4 0-7-3-7-7s3-7 7-7 7 3 7 7-3 7-7 7z"/>
4
+ <use xlink:href="defs.svg#icon-1"/>
5
+ </svg>
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: enshrined
3
  Donate link: https://wpsvg.com/
4
  Tags: svg, sanitize, upload, sanitise, security, svg upload, image, vector, file, graphic, media, mime
5
  Requires at least: 4.0
6
- Tested up to: 4.9.0
7
- Stable tag: 1.5.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -39,6 +39,10 @@ Install through the WordPress directory or download, unzip and upload the files
39
 
40
  == Changelog ==
41
 
 
 
 
 
42
  = 1.5.3 =
43
  * 1.5.2 introduced an issue that can freeze the media library. This fixes that issue. Sorry!
44
 
3
  Donate link: https://wpsvg.com/
4
  Tags: svg, sanitize, upload, sanitise, security, svg upload, image, vector, file, graphic, media, mime
5
  Requires at least: 4.0
6
+ Tested up to: 4.9.1
7
+ Stable tag: 1.6.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
39
 
40
  == Changelog ==
41
 
42
+ = 1.6.0 =
43
+ * Fairly big new feature - The library now allows `<use>` elements as long as they don't reference external files!
44
+ * You can now also embed safe image types within the SVG and not have them stripped (PNG, GIF, JPG)
45
+
46
  = 1.5.3 =
47
  * 1.5.2 introduced an issue that can freeze the media library. This fixes that issue. Sorry!
48
 
safe-svg.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Safe SVG
4
  Plugin URI: https://wpsvg.com/
5
  Description: Allows SVG uploads into WordPress and sanitizes the SVG before saving it
6
- Version: 1.5.3
7
  Author: Daryll Doyle
8
  Author URI: http://enshrined.co.uk
9
  Text Domain: safe-svg
3
  Plugin Name: Safe SVG
4
  Plugin URI: https://wpsvg.com/
5
  Description: Allows SVG uploads into WordPress and sanitizes the SVG before saving it
6
+ Version: 1.6.0
7
  Author: Daryll Doyle
8
  Author URI: http://enshrined.co.uk
9
  Text Domain: safe-svg