This commit is contained in:
parent
3836018c66
commit
8dfb49b566
@ -161,13 +161,13 @@ To override them, create a `config.php` file at the root of the project and chan
|
|||||||
|
|
||||||
By example, to override the default HTTP timeout value:
|
By example, to override the default HTTP timeout value:
|
||||||
|
|
||||||
# file config.php
|
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// My specific HTTP timeout (5 seconds)
|
// My specific HTTP timeout (5 seconds)
|
||||||
define('HTTP_TIMEOUT', 5);
|
define('HTTP_TIMEOUT', 5);
|
||||||
|
|
||||||
|
PS: This file must be a PHP file (nothing before the open tag `<?php`).
|
||||||
|
|
||||||
Actually, the following constants can be overrided:
|
Actually, the following constants can be overrided:
|
||||||
|
|
||||||
- `HTTP_TIMEOUT` => default value is 10 seconds
|
- `HTTP_TIMEOUT` => default value is 10 seconds
|
||||||
@ -189,6 +189,54 @@ you can save sessions in a custom directory.
|
|||||||
- Override the application variable like described above: `define('SESSION_SAVE_PATH', 'sessions');`
|
- Override the application variable like described above: `define('SESSION_SAVE_PATH', 'sessions');`
|
||||||
- Now, your sessions are saved in the directory `sessions`
|
- Now, your sessions are saved in the directory `sessions`
|
||||||
|
|
||||||
|
### How to override/extends the content filtering blacklist/whitelist?
|
||||||
|
|
||||||
|
Miniflux use [PicoFeed](https://github.com/fguillot/picoFeed) to parse the content of each item.
|
||||||
|
These variables are public static arrays, extends the actual array or replace it.
|
||||||
|
|
||||||
|
**Be careful, you can break everything by doing that!!!**
|
||||||
|
|
||||||
|
Put your modifications in your custom `config.php` like described above.
|
||||||
|
|
||||||
|
By example to add a new iframe whitelist:
|
||||||
|
|
||||||
|
\PicoFeed\Filter::$iframe_whitelist[] = 'http://www.kickstarter.com';
|
||||||
|
|
||||||
|
Or to replace the entire whitelist:
|
||||||
|
|
||||||
|
\PicoFeed\Filter::$iframe_whitelist = array('http://www.kickstarter.com');
|
||||||
|
|
||||||
|
Available variables:
|
||||||
|
|
||||||
|
// Allow only specified tags and attributes
|
||||||
|
\PicoFeed\Filter::$whitelist_tags
|
||||||
|
|
||||||
|
// Strip content of these tags
|
||||||
|
\PicoFeed\Filter::$blacklist_tags
|
||||||
|
|
||||||
|
// Allow only specified URI scheme
|
||||||
|
\PicoFeed\Filter::$whitelist_scheme
|
||||||
|
|
||||||
|
// List of attributes used for external resources: src and href
|
||||||
|
\PicoFeed\Filter::$media_attributes
|
||||||
|
|
||||||
|
// Blacklist of external resources
|
||||||
|
\PicoFeed\Filter::$media_blacklist
|
||||||
|
|
||||||
|
// Required attributes for tags, if the attribute is missing the tag is dropped
|
||||||
|
\PicoFeed\Filter::$required_attributes
|
||||||
|
|
||||||
|
// Add attribute to specified tags
|
||||||
|
\PicoFeed\Filter::$add_attributes
|
||||||
|
|
||||||
|
// Attributes that must be integer
|
||||||
|
\PicoFeed\Filter::$integer_attributes
|
||||||
|
|
||||||
|
// Iframe allowed source
|
||||||
|
\PicoFeed\Filter::$iframe_whitelist
|
||||||
|
|
||||||
|
For more details, have a look to the class `vendor/PicoFeed/Filter.php`.
|
||||||
|
|
||||||
### How to create a theme for Miniflux?
|
### How to create a theme for Miniflux?
|
||||||
|
|
||||||
It's very easy to write a custom theme for Miniflux.
|
It's very easy to write a custom theme for Miniflux.
|
||||||
|
@ -36,14 +36,7 @@ Router\before(function($action) {
|
|||||||
Response\csp(array(
|
Response\csp(array(
|
||||||
'media-src' => '*',
|
'media-src' => '*',
|
||||||
'img-src' => '*',
|
'img-src' => '*',
|
||||||
'frame-src' => implode(' ', array(
|
'frame-src' => implode(' ', \PicoFeed\Filter::$iframe_whitelist)
|
||||||
'http://www.youtube.com',
|
|
||||||
'https://www.youtube.com',
|
|
||||||
'http://player.vimeo.com',
|
|
||||||
'https://player.vimeo.com',
|
|
||||||
'http://www.dailymotion.com',
|
|
||||||
'https://www.dailymotion.com',
|
|
||||||
))
|
|
||||||
));
|
));
|
||||||
|
|
||||||
Response\xframe();
|
Response\xframe();
|
||||||
|
88
vendor/PicoFeed/Filter.php
vendored
88
vendor/PicoFeed/Filter.php
vendored
@ -10,7 +10,8 @@ class Filter
|
|||||||
private $empty_tags = array();
|
private $empty_tags = array();
|
||||||
private $strip_content = false;
|
private $strip_content = false;
|
||||||
|
|
||||||
public $allowed_tags = array(
|
// Allow only these tags and attributes
|
||||||
|
public static $whitelist_tags = array(
|
||||||
'audio' => array('controls', 'src'),
|
'audio' => array('controls', 'src'),
|
||||||
'video' => array('poster', 'controls', 'height', 'width', 'src'),
|
'video' => array('poster', 'controls', 'height', 'width', 'src'),
|
||||||
'source' => array('src', 'type'),
|
'source' => array('src', 'type'),
|
||||||
@ -51,12 +52,14 @@ class Filter
|
|||||||
'q' => array('cite')
|
'q' => array('cite')
|
||||||
);
|
);
|
||||||
|
|
||||||
public $strip_tags_content = array(
|
// Strip content of these tags
|
||||||
|
public static $blacklist_tags = array(
|
||||||
'script'
|
'script'
|
||||||
);
|
);
|
||||||
|
|
||||||
// http://en.wikipedia.org/wiki/URI_scheme
|
// Allowed URI scheme
|
||||||
public $allowed_protocols = array(
|
// For a complete list go to http://en.wikipedia.org/wiki/URI_scheme
|
||||||
|
public static $scheme_whitelist = array(
|
||||||
'//',
|
'//',
|
||||||
'data:image/png;base64,',
|
'data:image/png;base64,',
|
||||||
'data:image/gif;base64,',
|
'data:image/gif;base64,',
|
||||||
@ -92,12 +95,15 @@ class Filter
|
|||||||
'tel:',
|
'tel:',
|
||||||
);
|
);
|
||||||
|
|
||||||
public $protocol_attributes = array(
|
// Attributes used for external resources
|
||||||
|
public static $media_attributes = array(
|
||||||
'src',
|
'src',
|
||||||
'href',
|
'href',
|
||||||
|
'poster',
|
||||||
);
|
);
|
||||||
|
|
||||||
public $blacklist_media = array(
|
// Blacklisted resources
|
||||||
|
public static $media_blacklist = array(
|
||||||
'feeds.feedburner.com',
|
'feeds.feedburner.com',
|
||||||
'share.feedsportal.com',
|
'share.feedsportal.com',
|
||||||
'da.feedsportal.com',
|
'da.feedsportal.com',
|
||||||
@ -119,20 +125,32 @@ class Filter
|
|||||||
'plus.google.com/share',
|
'plus.google.com/share',
|
||||||
'www.gstatic.com/images/icons/gplus-16.png',
|
'www.gstatic.com/images/icons/gplus-16.png',
|
||||||
'www.gstatic.com/images/icons/gplus-32.png',
|
'www.gstatic.com/images/icons/gplus-32.png',
|
||||||
'www.gstatic.com/images/icons/gplus-64.png'
|
'www.gstatic.com/images/icons/gplus-64.png',
|
||||||
);
|
);
|
||||||
|
|
||||||
public $required_attributes = array(
|
// Mandatory attributes for specified tags
|
||||||
|
public static $required_attributes = array(
|
||||||
'a' => array('href'),
|
'a' => array('href'),
|
||||||
'img' => array('src'),
|
'img' => array('src'),
|
||||||
'iframe' => array('src')
|
'iframe' => array('src'),
|
||||||
|
'audio' => array('src'),
|
||||||
|
'source' => array('src'),
|
||||||
);
|
);
|
||||||
|
|
||||||
public $add_attributes = array(
|
// Add attributes to specified tags
|
||||||
|
public static $add_attributes = array(
|
||||||
'a' => 'rel="noreferrer" target="_blank"'
|
'a' => 'rel="noreferrer" target="_blank"'
|
||||||
);
|
);
|
||||||
|
|
||||||
public $iframe_allowed_resources = array(
|
// Attributes that must be integer
|
||||||
|
public static $integer_attributes = array(
|
||||||
|
'width',
|
||||||
|
'height',
|
||||||
|
'frameborder',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Iframe source whitelist, everything else is ignored
|
||||||
|
public static $iframe_whitelist = array(
|
||||||
'//www.youtube.com',
|
'//www.youtube.com',
|
||||||
'http://www.youtube.com/',
|
'http://www.youtube.com/',
|
||||||
'https://www.youtube.com/',
|
'https://www.youtube.com/',
|
||||||
@ -218,12 +236,12 @@ class Filter
|
|||||||
$attr_data .= ' '.$attribute.'="'.$this->getAbsoluteUrl($value, $this->url).'"';
|
$attr_data .= ' '.$attribute.'="'.$this->getAbsoluteUrl($value, $this->url).'"';
|
||||||
$used_attributes[] = $attribute;
|
$used_attributes[] = $attribute;
|
||||||
}
|
}
|
||||||
else if ($this->isAllowedProtocol($value) && ! $this->isBlacklistMedia($value)) {
|
else if ($this->isAllowedProtocol($value) && ! $this->isBlacklistedMedia($value)) {
|
||||||
|
|
||||||
if ($attribute == 'src' &&
|
if ($attribute == 'src' &&
|
||||||
isset($attributes['data-src']) &&
|
isset($attributes['data-src']) &&
|
||||||
$this->isAllowedProtocol($attributes['data-src']) &&
|
$this->isAllowedProtocol($attributes['data-src']) &&
|
||||||
! $this->isBlacklistMedia($attributes['data-src'])) {
|
! $this->isBlacklistedMedia($attributes['data-src'])) {
|
||||||
|
|
||||||
$value = $attributes['data-src'];
|
$value = $attributes['data-src'];
|
||||||
}
|
}
|
||||||
@ -232,7 +250,7 @@ class Filter
|
|||||||
$used_attributes[] = $attribute;
|
$used_attributes[] = $attribute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if ($this->validateAttributeValue($attribute, $value)) {
|
||||||
|
|
||||||
$attr_data .= ' '.$attribute.'="'.$value.'"';
|
$attr_data .= ' '.$attribute.'="'.$value.'"';
|
||||||
$used_attributes[] = $attribute;
|
$used_attributes[] = $attribute;
|
||||||
@ -241,9 +259,9 @@ class Filter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for required attributes
|
// Check for required attributes
|
||||||
if (isset($this->required_attributes[$name])) {
|
if (isset(self::$required_attributes[$name])) {
|
||||||
|
|
||||||
foreach ($this->required_attributes[$name] as $required_attribute) {
|
foreach (self::$required_attributes[$name] as $required_attribute) {
|
||||||
|
|
||||||
if (! in_array($required_attribute, $used_attributes)) {
|
if (! in_array($required_attribute, $used_attributes)) {
|
||||||
|
|
||||||
@ -258,9 +276,9 @@ class Filter
|
|||||||
$this->data .= '<'.$name.$attr_data;
|
$this->data .= '<'.$name.$attr_data;
|
||||||
|
|
||||||
// Add custom attributes
|
// Add custom attributes
|
||||||
if (isset($this->add_attributes[$name])) {
|
if (isset(self::$add_attributes[$name])) {
|
||||||
|
|
||||||
$this->data .= ' '.$this->add_attributes[$name].' ';
|
$this->data .= ' '.self::$add_attributes[$name].' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
// If img or br, we don't close it here
|
// If img or br, we don't close it here
|
||||||
@ -268,7 +286,7 @@ class Filter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($name, $this->strip_tags_content)) {
|
if (in_array($name, self::$blacklist_tags)) {
|
||||||
|
|
||||||
$this->strip_content = true;
|
$this->strip_content = true;
|
||||||
}
|
}
|
||||||
@ -294,8 +312,6 @@ class Filter
|
|||||||
|
|
||||||
public function getAbsoluteUrl($path, $url)
|
public function getAbsoluteUrl($path, $url)
|
||||||
{
|
{
|
||||||
//if (! filter_var($url, FILTER_VALIDATE_URL)) return '';
|
|
||||||
|
|
||||||
$components = parse_url($url);
|
$components = parse_url($url);
|
||||||
|
|
||||||
if (! isset($components['scheme'])) $components['scheme'] = 'http';
|
if (! isset($components['scheme'])) $components['scheme'] = 'http';
|
||||||
@ -325,12 +341,10 @@ class Filter
|
|||||||
$length = strlen($url_path);
|
$length = strlen($url_path);
|
||||||
|
|
||||||
if ($length > 1 && $url_path{$length - 1} !== '/') {
|
if ($length > 1 && $url_path{$length - 1} !== '/') {
|
||||||
|
|
||||||
$url_path = dirname($url_path).'/';
|
$url_path = dirname($url_path).'/';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (substr($path, 0, 2) === './') {
|
if (substr($path, 0, 2) === './') {
|
||||||
|
|
||||||
$path = substr($path, 2);
|
$path = substr($path, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,35 +356,33 @@ class Filter
|
|||||||
public function isRelativePath($value)
|
public function isRelativePath($value)
|
||||||
{
|
{
|
||||||
if (strpos($value, 'data:') === 0) return false;
|
if (strpos($value, 'data:') === 0) return false;
|
||||||
|
|
||||||
return strpos($value, '://') === false && strpos($value, '//') !== 0;
|
return strpos($value, '://') === false && strpos($value, '//') !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function isAllowedTag($name)
|
public function isAllowedTag($name)
|
||||||
{
|
{
|
||||||
return isset($this->allowed_tags[$name]);
|
return isset(self::$whitelist_tags[$name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function isAllowedAttribute($tag, $attribute)
|
public function isAllowedAttribute($tag, $attribute)
|
||||||
{
|
{
|
||||||
return in_array($attribute, $this->allowed_tags[$tag]);
|
return in_array($attribute, self::$whitelist_tags[$tag]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function isResource($attribute)
|
public function isResource($attribute)
|
||||||
{
|
{
|
||||||
return in_array($attribute, $this->protocol_attributes);
|
return in_array($attribute, self::$media_attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function isAllowedIframeResource($value)
|
public function isAllowedIframeResource($value)
|
||||||
{
|
{
|
||||||
foreach ($this->iframe_allowed_resources as $url) {
|
foreach (self::$iframe_whitelist as $url) {
|
||||||
|
|
||||||
if (strpos($value, $url) === 0) {
|
if (strpos($value, $url) === 0) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,10 +393,9 @@ class Filter
|
|||||||
|
|
||||||
public function isAllowedProtocol($value)
|
public function isAllowedProtocol($value)
|
||||||
{
|
{
|
||||||
foreach ($this->allowed_protocols as $protocol) {
|
foreach (self::$scheme_whitelist as $protocol) {
|
||||||
|
|
||||||
if (strpos($value, $protocol) === 0) {
|
if (strpos($value, $protocol) === 0) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,12 +404,11 @@ class Filter
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function isBlacklistMedia($resource)
|
public function isBlacklistedMedia($resource)
|
||||||
{
|
{
|
||||||
foreach ($this->blacklist_media as $name) {
|
foreach (self::$media_blacklist as $name) {
|
||||||
|
|
||||||
if (strpos($resource, $name) !== false) {
|
if (strpos($resource, $name) !== false) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,4 +423,14 @@ class Filter
|
|||||||
isset($attributes['height']) && isset($attributes['width']) &&
|
isset($attributes['height']) && isset($attributes['width']) &&
|
||||||
$attributes['height'] == 1 && $attributes['width'] == 1;
|
$attributes['height'] == 1 && $attributes['width'] == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function validateAttributeValue($attribute, $value)
|
||||||
|
{
|
||||||
|
if (in_array($attribute, self::$integer_attributes)) {
|
||||||
|
return ctype_digit($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user