From 6da44b7c47f3d8aa3cefe3fb480d4e46a1c91168 Mon Sep 17 00:00:00 2001 From: n1rwana Date: Thu, 3 Aug 2023 01:35:20 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=91=D0=B5=D0=B7=D0=BE=D0=BF=D0=B0=D1=81?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=B8=20=D0=BF=D1=80=D0=BE=D0=BA=D1=81=D0=B8=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Web/Models/Entities/Note.php | 30 ++++++++++++- Web/Presenters/ImagesProxyPresenter.php | 56 +++++++++++++++++++++++++ Web/di.yml | 1 + Web/routes.yml | 2 + 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 Web/Presenters/ImagesProxyPresenter.php diff --git a/Web/Models/Entities/Note.php b/Web/Models/Entities/Note.php index 37d9ac29..b2a832e3 100644 --- a/Web/Models/Entities/Note.php +++ b/Web/Models/Entities/Note.php @@ -2,6 +2,33 @@ namespace openvk\Web\Models\Entities; use HTMLPurifier_Config; use HTMLPurifier; +use HTMLPurifier_Filter; + +class SecurityFilter extends HTMLPurifier_Filter +{ + public function preFilter($html, $config, $context) + { + $html = preg_replace_callback( + '/]*src\s*=\s*["\']([^"\']*)["\'][^>]*>/i', + function ($matches) { + $originalSrc = $matches[1]; + $encodedSrc = '/image.php?url=' . base64_encode($originalSrc); + return str_replace($originalSrc, $encodedSrc, $matches[0]); + }, + $html + ); + + return preg_replace_callback( + '/]*href\s*=\s*["\']([^"\']*)["\'][^>]*>/i', + function ($matches) { + $originalHref = $matches[1]; + $encodedHref = '/away.php?to=' . urlencode($originalHref); + return str_replace($originalHref, $encodedHref, $matches[0]); + }, + $html + ); + } +} class Note extends Postable { @@ -74,7 +101,8 @@ class Note extends Postable $config->set("Attr.AllowedClasses", [ "underline", ]); - + $config->set('Filter.Custom', [new SecurityFilter()]); + $source = NULL; if(is_null($this->getRecord())) { if(isset($this->changes["source"])) diff --git a/Web/Presenters/ImagesProxyPresenter.php b/Web/Presenters/ImagesProxyPresenter.php new file mode 100644 index 00000000..f58cb309 --- /dev/null +++ b/Web/Presenters/ImagesProxyPresenter.php @@ -0,0 +1,56 @@ +image("image/png", strlen($placeholder), $placeholder); + } + + public function renderIndex(): void + { + $url = base64_decode($this->requestParam("url")); + if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) { + $this->placeholder(); + } + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_HEADER => 0, + CURLOPT_URL => $url, + CURLOPT_USERAGENT => OPENVK_ROOT_CONF["openvk"]["appearance"]["name"] . ' Images Proxy/1.0', + CURLOPT_REFERER => "https://$_SERVER[SERVER_NAME]/", + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_BINARYTRANSFER => 1, + ]); + + $raw = curl_exec($ch); + $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); + $contentSize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); + + curl_close($ch); + + if ($raw && str_contains($contentType, "image")) { + $this->image($contentType, $contentSize, $raw); + } else { + $this->placeholder(); + } + } +} diff --git a/Web/di.yml b/Web/di.yml index 3363c5de..8cd39417 100644 --- a/Web/di.yml +++ b/Web/di.yml @@ -49,3 +49,4 @@ services: - openvk\Web\Models\Repositories\BannedLinks - openvk\Web\Models\Repositories\ChandlerGroups - openvk\Web\Presenters\MaintenancePresenter + - openvk\Web\Presenters\ImagesProxyPresenter diff --git a/Web/routes.yml b/Web/routes.yml index d1a0e7ae..d69da10f 100644 --- a/Web/routes.yml +++ b/Web/routes.yml @@ -349,6 +349,8 @@ routes: handler: "About->dev" - url: "/tour" handler: "About->tour" + - url: "/image.php" + handler: "ImagesProxy->index" - url: "/{?shortCode}" handler: "UnknownTextRouteStrategy->delegate" placeholders: From 04dbede4c605f3e0fe395b8d268f069a04271767 Mon Sep 17 00:00:00 2001 From: n1rwana Date: Thu, 3 Aug 2023 11:25:35 +0300 Subject: [PATCH 2/2] Proxy Improvements --- Web/Models/Entities/Note.php | 37 ++++++++++++++++--------- Web/Presenters/ImagesProxyPresenter.php | 9 +++++- openvk-example.yml | 5 ++++ 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Web/Models/Entities/Note.php b/Web/Models/Entities/Note.php index b2a832e3..932c1fc9 100644 --- a/Web/Models/Entities/Note.php +++ b/Web/Models/Entities/Note.php @@ -12,8 +12,17 @@ class SecurityFilter extends HTMLPurifier_Filter '/]*src\s*=\s*["\']([^"\']*)["\'][^>]*>/i', function ($matches) { $originalSrc = $matches[1]; - $encodedSrc = '/image.php?url=' . base64_encode($originalSrc); - return str_replace($originalSrc, $encodedSrc, $matches[0]); + $src = $originalSrc; + if (!str_contains($src, "/image.php?url=")) { + $src = '/image.php?url=' . base64_encode($originalSrc); + } else { + if (!OPENVK_ROOT_CONF["openvk"]["preferences"]["imagesProxy"]["replaceInNotes"]) { + $src = preg_replace_callback('/(.*)\/image\.php\?url=(.*)/i', function ($matches) { + return base64_decode($matches[2]); + }, $src); + } + } + return str_replace($originalSrc, $src, $matches[0]); }, $html ); @@ -34,7 +43,7 @@ class Note extends Postable { protected $tableName = "notes"; - protected function renderHTML(): string + protected function renderHTML(?string $content = NULL): string { $config = HTMLPurifier_Config::createDefault(); $config->set("Attr.AllowedClasses", []); @@ -103,14 +112,16 @@ class Note extends Postable ]); $config->set('Filter.Custom', [new SecurityFilter()]); - $source = NULL; - if(is_null($this->getRecord())) { - if(isset($this->changes["source"])) - $source = $this->changes["source"]; - else - throw new \LogicException("Can't render note without content set."); - } else { - $source = $this->getRecord()->source; + $source = $content; + if (!$source) { + if (is_null($this->getRecord())) { + if (isset($this->changes["source"])) + $source = $this->changes["source"]; + else + throw new \LogicException("Can't render note without content set."); + } else { + $source = $this->getRecord()->source; + } } $purifier = new HTMLPurifier($config); @@ -138,8 +149,8 @@ class Note extends Postable $this->setCached_Content($cached); $this->save(); } - - return $cached; + + return $this->renderHTML($cached); } function getSource(): string diff --git a/Web/Presenters/ImagesProxyPresenter.php b/Web/Presenters/ImagesProxyPresenter.php index f58cb309..6a86b21f 100644 --- a/Web/Presenters/ImagesProxyPresenter.php +++ b/Web/Presenters/ImagesProxyPresenter.php @@ -26,7 +26,14 @@ final class ImagesProxyPresenter extends OpenVKPresenter public function renderIndex(): void { - $url = base64_decode($this->requestParam("url")); + $this->assertUserLoggedIn(); + + $url = $this->requestParam("url"); + if (OPENVK_ROOT_CONF["openvk"]["preferences"]["imagesProxy"]["settings"]["base64_decode_url"]) { + $url = base64_decode($url); + } + + $url = OPENVK_ROOT_CONF["openvk"]["preferences"]["imagesProxy"]["settings"]["url_prefix"] . $url; if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) { $this->placeholder(); } diff --git a/openvk-example.yml b/openvk-example.yml index e3fd1c3a..8cf75b1d 100644 --- a/openvk-example.yml +++ b/openvk-example.yml @@ -102,6 +102,11 @@ openvk: fartscroll: false testLabel: false defaultMobileTheme: "" + imagesProxy: + replaceInNotes: true + settings: + url_prefix: "" + base64_decode_url: true telemetry: plausible: