From 3cef6e4824444d0e3418d3ac2ef47ee61a720b49 Mon Sep 17 00:00:00 2001
From: mrilyew <99399973+mrilyew@users.noreply.github.com>
Date: Sun, 8 Jun 2025 11:08:53 +0300
Subject: [PATCH] add list of allowed hosts in notes images
Co-Authored-By: n1rwana <93197434+n1rwana@users.noreply.github.com>
---
Web/Models/Entities/Note.php | 51 +++++++++++++++++++-----
Web/Presenters/InternalAPIPresenter.php | 22 ++++++++++
Web/routes.yml | 2 +
Web/static/img/fn_placeholder.jpg | Bin 0 -> 15203 bytes
openvk-example.yml | 3 ++
5 files changed, 69 insertions(+), 9 deletions(-)
create mode 100644 Web/static/img/fn_placeholder.jpg
diff --git a/Web/Models/Entities/Note.php b/Web/Models/Entities/Note.php
index a44c421b..b9829822 100644
--- a/Web/Models/Entities/Note.php
+++ b/Web/Models/Entities/Note.php
@@ -6,12 +6,42 @@ 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];
+ $src = $originalSrc;
+
+ if (OPENVK_ROOT_CONF["openvk"]["preferences"]["notes"]["disableHotlinking"] ?? true) {
+ if (!str_contains($src, "/image.php?url=")) {
+ $src = '/image.php?url=' . base64_encode($originalSrc);
+ } /*else {
+ $src = preg_replace_callback('/(.*)\/image\.php\?url=(.*)/i', function ($matches) {
+ return base64_decode($matches[2]);
+ }, $src);
+ }*/
+ }
+
+ return str_replace($originalSrc, $src, $matches[0]);
+ },
+ $html
+ );
+
+ return $html;
+ }
+}
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", []);
@@ -78,16 +108,19 @@ 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"])) {
- $source = $this->changes["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 {
- throw new \LogicException("Can't render note without content set.");
+ $source = $this->getRecord()->source;
}
- } else {
- $source = $this->getRecord()->source;
}
$purifier = new HTMLPurifier($config);
@@ -117,7 +150,7 @@ class Note extends Postable
$this->save();
}
- return $cached;
+ return $this->renderHTML($cached);
}
public function getSource(): string
diff --git a/Web/Presenters/InternalAPIPresenter.php b/Web/Presenters/InternalAPIPresenter.php
index 464059cb..eb9daac2 100644
--- a/Web/Presenters/InternalAPIPresenter.php
+++ b/Web/Presenters/InternalAPIPresenter.php
@@ -176,4 +176,26 @@ final class InternalAPIPresenter extends OpenVKPresenter
exit('');
}
}
+
+ public function renderImageFilter()
+ {
+ $is_enabled = OPENVK_ROOT_CONF["openvk"]["preferences"]["notes"]["disableHotlinking"] ?? true;
+ $allowed_hosts = OPENVK_ROOT_CONF["openvk"]["preferences"]["notes"]["allowedHosts"] ?? [];
+
+ $url = $this->requestParam("url");
+ $url = base64_decode($url);
+
+ if (!$is_enabled) {
+ $this->redirect($url);
+ }
+
+ $url_parsed = parse_url($url);
+ $host = $url_parsed['host'];
+
+ if (in_array($host, $allowed_hosts)) {
+ $this->redirect($url);
+ } else {
+ $this->redirect('/assets/packages/static/openvk/img/fn_placeholder.jpg');
+ }
+ }
}
diff --git a/Web/routes.yml b/Web/routes.yml
index 9738b740..f1cf2af6 100644
--- a/Web/routes.yml
+++ b/Web/routes.yml
@@ -413,6 +413,8 @@ routes:
handler: "InternalAPI->getPhotosFromPost"
- url: "/iapi/getPostTemplate/{num}_{num}"
handler: "InternalAPI->getPostTemplate"
+ - url: "/image.php"
+ handler: "InternalAPI->imageFilter"
- url: "/tour"
handler: "About->tour"
- url: "/fave"
diff --git a/Web/static/img/fn_placeholder.jpg b/Web/static/img/fn_placeholder.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..25b7f914d560573f05a2d19792a6cb658bfcaabc
GIT binary patch
literal 15203
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