[Embed][StoreRemoteMedia] Re-add {white,black}list check config

This commit is contained in:
Diogo Peralta Cordeiro 2021-08-18 14:15:30 +01:00 committed by Hugo Sales
parent de444a2a5a
commit 177801c81b
Signed by: someonewithpc
GPG Key ID: 7D0C7EAFC9D835A0
2 changed files with 101 additions and 29 deletions

View File

@ -77,12 +77,15 @@ class Embed extends Plugin
* Settings which can be set in social.local.yaml * Settings which can be set in social.local.yaml
* WARNING, these are _regexps_ (slashes added later). Always escape your dots and end ('$') your strings * WARNING, these are _regexps_ (slashes added later). Always escape your dots and end ('$') your strings
*/ */
public bool $check_whitelist = false;
public bool $check_blacklist = false;
public array $domain_whitelist = [ public array $domain_whitelist = [
// hostname => service provider // hostname
'.*' => '', // Default to allowing any host '.*', // Default to allowing any host
]; ];
public array $domain_blacklist = [];
public bool $store_image = true; // Whether to maintain a copy of the original media or only a thumbnail of it // Whether to maintain a copy of the original media or only a thumbnail of it
public bool $store_image = true;
public ?int $thumbnail_width; public ?int $thumbnail_width;
public ?int $thumbnail_height; public ?int $thumbnail_height;
public ?int $max_size; public ?int $max_size;
@ -198,28 +201,6 @@ class Embed extends Plugin
return Event::next; return Event::next;
} }
/**
* @param string $url
*
* @return bool true if allowed by the lists, false otherwise
*/
private function allowedLink(string $url): bool
{
return true;
if ($this->check_whitelist ?? false) {
return false; // indicates "no check made"
}
$host = parse_url($url, PHP_URL_HOST);
foreach ($this->domain_whitelist as $regex => $provider) {
if (preg_match("/{$regex}/", $host)) {
return $provider; // we trust this source, return provider name
}
}
return false;
}
/** /**
* This code executes when GNU social creates the page routing, and we hook * This code executes when GNU social creates the page routing, and we hook
* on this event to add our action handler for Embed. * on this event to add our action handler for Embed.
@ -231,6 +212,7 @@ class Embed extends Plugin
* @return bool * @return bool
* *
* *
*
*/ */
public function onAddRoute(RouteLoader $m): bool public function onAddRoute(RouteLoader $m): bool
{ {
@ -301,10 +283,11 @@ class Embed extends Plugin
* @param Link $link * @param Link $link
* @param Note $note * @param Note $note
* *
*@throws DuplicateFoundException * @throws DuplicateFoundException
* *
* @return bool * @return bool
* *
*
*/ */
public function onNewLinkFromNote(Link $link, Note $note): bool public function onNewLinkFromNote(Link $link, Note $note): bool
{ {
@ -362,6 +345,39 @@ class Embed extends Plugin
return Event::stop; return Event::stop;
} }
/**
* @param string $url
*
* @return bool true if allowed by the lists, false otherwise
*/
private function allowedLink(string $url): bool
{
$passed_whitelist = !$this->check_whitelist;
$passed_blacklist = !$this->check_blacklist;
if ($this->check_whitelist) {
$passed_whitelist = false; // don't trust be default
$host = parse_url($url, PHP_URL_HOST);
foreach ($this->domain_whitelist as $regex => $provider) {
if (preg_match("/{$regex}/", $host)) {
$passed_whitelist = true; // we trust this source
}
}
}
if ($this->check_blacklist) {
// assume it passed by default
$host = parse_url($url, PHP_URL_HOST);
foreach ($this->domain_blacklist as $regex => $provider) {
if (preg_match("/{$regex}/", $host)) {
$passed_blacklist = false; // we blocked this source
}
}
}
return $passed_whitelist && $passed_blacklist;
}
/** /**
* Perform an oEmbed or OpenGraph lookup for the given $url. * Perform an oEmbed or OpenGraph lookup for the given $url.
* *
@ -481,6 +497,7 @@ class Embed extends Plugin
* @throws ServerException * @throws ServerException
* *
* @return bool true hook value * @return bool true hook value
*
*/ */
public function onPluginVersion(array &$versions): bool public function onPluginVersion(array &$versions): bool
{ {

View File

@ -22,6 +22,8 @@ use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\HTTPClient; use App\Core\HTTPClient;
use function App\Core\I18n\_m;
use App\Core\Log;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Entity\AttachmentThumbnail; use App\Entity\AttachmentThumbnail;
use App\Entity\AttachmentToLink; use App\Entity\AttachmentToLink;
@ -54,7 +56,19 @@ class StoreRemoteMedia extends Plugin
return '3.0.0'; return '3.0.0';
} }
public bool $store_original = false; // Whether to maintain a copy of the original media or only a thumbnail of it /**
* Settings which can be set in social.local.yaml
* WARNING, these are _regexps_ (slashes added later). Always escape your dots and end ('$') your strings
*/
public bool $check_whitelist = false;
public bool $check_blacklist = false;
public array $domain_whitelist = [
// hostname
'.*', // Default to allowing any host
];
public array $domain_blacklist = [];
// Whether to maintain a copy of the original media or only a thumbnail of it
public bool $store_original = false;
public ?int $thumbnail_width; public ?int $thumbnail_width;
public ?int $thumbnail_height; public ?int $thumbnail_height;
public ?int $max_size; public ?int $max_size;
@ -64,6 +78,7 @@ class StoreRemoteMedia extends Plugin
{ {
return $this->store_original; return $this->store_original;
} }
private function getThumbnailWidth(): int private function getThumbnailWidth(): int
{ {
return $this->thumbnail_width ?? Common::config('thumbnail', 'width'); return $this->thumbnail_width ?? Common::config('thumbnail', 'width');
@ -88,11 +103,12 @@ class StoreRemoteMedia extends Plugin
* @param Link $link * @param Link $link
* @param Note $note * @param Note $note
* *
* @throws DuplicateFoundException
* @throws ServerException * @throws ServerException
* @throws TemporaryFileException * @throws TemporaryFileException
* @throws DuplicateFoundException
* *
* @return bool * @return bool
*
*/ */
public function onNewLinkFromNote(Link $link, Note $note): bool public function onNewLinkFromNote(Link $link, Note $note): bool
{ {
@ -101,6 +117,12 @@ class StoreRemoteMedia extends Plugin
return Event::next; return Event::next;
} }
// Is this URL trusted?
if (!$this->allowedLink($link->getUrl())) {
Log::info("Blocked URL ({$link->getUrl()}) in StoreRemoteMedia->onNewLinkFromNote.");
return Event::next;
}
// Have we handled it already? // Have we handled it already?
$attachment_to_link = DB::find('attachment_to_link', $attachment_to_link = DB::find('attachment_to_link',
['link_id' => $link->getId()]); ['link_id' => $link->getId()]);
@ -165,6 +187,39 @@ class StoreRemoteMedia extends Plugin
} }
} }
/**
* @param string $url
*
* @return bool true if allowed by the lists, false otherwise
*/
private function allowedLink(string $url): bool
{
$passed_whitelist = !$this->check_whitelist;
$passed_blacklist = !$this->check_blacklist;
if ($this->check_whitelist) {
$passed_whitelist = false; // don't trust be default
$host = parse_url($url, PHP_URL_HOST);
foreach ($this->domain_whitelist as $regex => $provider) {
if (preg_match("/{$regex}/", $host)) {
$passed_whitelist = true; // we trust this source
}
}
}
if ($this->check_blacklist) {
// assume it passed by default
$host = parse_url($url, PHP_URL_HOST);
foreach ($this->domain_blacklist as $regex => $provider) {
if (preg_match("/{$regex}/", $host)) {
$passed_blacklist = false; // we blocked this source
}
}
}
return $passed_whitelist && $passed_blacklist;
}
/** /**
* Event raised when GNU social polls the plugin for information about it. * Event raised when GNU social polls the plugin for information about it.
* Adds this plugin's version information to $versions array * Adds this plugin's version information to $versions array