1
0
mirror of https://github.com/erusev/parsedown.git synced 2023-08-10 21:13:06 +03:00

Move url sanitisation out of Element class

This commit is contained in:
Aidan Woods 2019-02-10 17:24:00 +00:00
parent a681cf631c
commit 41fb6b0d43
No known key found for this signature in database
GPG Key ID: 9A6A8EFAA512BBB9
4 changed files with 67 additions and 57 deletions

View File

@ -8,6 +8,7 @@ use Erusev\Parsedown\Components\Inline;
use Erusev\Parsedown\Configurables\SafeMode; use Erusev\Parsedown\Configurables\SafeMode;
use Erusev\Parsedown\Html\Renderables\Element; use Erusev\Parsedown\Html\Renderables\Element;
use Erusev\Parsedown\Html\Renderables\Text; use Erusev\Parsedown\Html\Renderables\Text;
use Erusev\Parsedown\Html\Sanitisation\UrlSanitiser;
use Erusev\Parsedown\Parsedown; use Erusev\Parsedown\Parsedown;
use Erusev\Parsedown\Parsing\Excerpt; use Erusev\Parsedown\Parsing\Excerpt;
use Erusev\Parsedown\State; use Erusev\Parsedown\State;
@ -84,7 +85,7 @@ final class Image implements Inline
} }
if ($State->get(SafeMode::class)->isEnabled()) { if ($State->get(SafeMode::class)->isEnabled()) {
$attributes['src'] = Element::filterUnsafeUrl($attributes['src']); $attributes['src'] = UrlSanitiser::filter($attributes['src']);
} }
return Element::selfClosing('img', $attributes); return Element::selfClosing('img', $attributes);

View File

@ -10,6 +10,7 @@ use Erusev\Parsedown\Configurables\InlineTypes;
use Erusev\Parsedown\Configurables\SafeMode; use Erusev\Parsedown\Configurables\SafeMode;
use Erusev\Parsedown\Html\Renderables\Element; use Erusev\Parsedown\Html\Renderables\Element;
use Erusev\Parsedown\Html\Renderables\Text; use Erusev\Parsedown\Html\Renderables\Text;
use Erusev\Parsedown\Html\Sanitisation\UrlSanitiser;
use Erusev\Parsedown\Parsedown; use Erusev\Parsedown\Parsedown;
use Erusev\Parsedown\Parsing\Excerpt; use Erusev\Parsedown\Parsing\Excerpt;
use Erusev\Parsedown\State; use Erusev\Parsedown\State;
@ -124,7 +125,7 @@ final class Link implements Inline
} }
if ($State->get(SafeMode::class)->isEnabled()) { if ($State->get(SafeMode::class)->isEnabled()) {
$attributes['href'] = Element::filterUnsafeUrl($attributes['href']); $attributes['href'] = UrlSanitiser::filter($attributes['href']);
} }
$State = $State->setting( $State = $State->setting(

View File

@ -62,25 +62,6 @@ final class Element implements Renderable
'basefont' => true, 'basefont' => true,
]; ];
/** @var string[] */
public static $COMMON_SCHEMES = [
'http://',
'https://',
'ftp://',
'ftps://',
'mailto:',
'tel:',
'data:image/png;base64,',
'data:image/gif;base64,',
'data:image/jpeg;base64,',
'irc:',
'ircs:',
'git:',
'ssh:',
'news:',
'steam:',
];
/** @var string */ /** @var string */
private $name; private $name;
@ -224,40 +205,4 @@ final class Element implements Renderable
return $html; return $html;
} }
/**
* @param string $url
* @param string[]|null $permittedSchemes
* @return string
*/
public static function filterUnsafeUrl($url, $permittedSchemes = null)
{
if (! isset($permittedSchemes)) {
$permittedSchemes = self::$COMMON_SCHEMES;
}
foreach ($permittedSchemes as $scheme) {
if (self::striAtStart($url, $scheme)) {
return $url;
}
}
return \str_replace(':', '%3A', $url);
}
/**
* @param string $string
* @param string $needle
* @return bool
*/
private static function striAtStart($string, $needle)
{
$len = \strlen($needle);
if ($len > \strlen($string)) {
return false;
} else {
return \strtolower(\substr($string, 0, $len)) === \strtolower($needle);
}
}
} }

View File

@ -0,0 +1,63 @@
<?php
namespace Erusev\Parsedown\Html\Sanitisation;
final class UrlSanitiser
{
/** @var string[] */
private static $COMMON_SCHEMES = [
'http://',
'https://',
'ftp://',
'ftps://',
'mailto:',
'tel:',
'data:image/png;base64,',
'data:image/gif;base64,',
'data:image/jpeg;base64,',
'irc:',
'ircs:',
'git:',
'ssh:',
'news:',
'steam:',
];
/**
* Disable literal intepretation of unknown scheme in $url. Returns the
* filtered version of $url.
* @param string $url
* @param string[]|null $permittedSchemes
* @return string
*/
public static function filter($url, $permittedSchemes = null)
{
if (! isset($permittedSchemes)) {
$permittedSchemes = self::$COMMON_SCHEMES;
}
foreach ($permittedSchemes as $scheme) {
if (self::striAtStart($url, $scheme)) {
return $url;
}
}
return \str_replace(':', '%3A', $url);
}
/**
* @param string $string
* @param string $needle
* @return bool
*/
private static function striAtStart($string, $needle)
{
$len = \strlen($needle);
if ($len > \strlen($string)) {
return false;
} else {
return \strtolower(\substr($string, 0, $len)) === \strtolower($needle);
}
}
}