diff --git a/Web/Models/Entities/Note.php b/Web/Models/Entities/Note.php
index 37d9ac29..932c1fc9 100644
--- a/Web/Models/Entities/Note.php
+++ b/Web/Models/Entities/Note.php
@@ -2,12 +2,48 @@
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 (!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
+ );
+
+ 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
{
protected $tableName = "notes";
- protected function renderHTML(): string
+ protected function renderHTML(?string $content = NULL): string
{
$config = HTMLPurifier_Config::createDefault();
$config->set("Attr.AllowedClasses", []);
@@ -74,15 +110,18 @@ class Note extends Postable
$config->set("Attr.AllowedClasses", [
"underline",
]);
-
- $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;
+ $config->set('Filter.Custom', [new SecurityFilter()]);
+
+ $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);
@@ -110,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
new file mode 100644
index 00000000..6a86b21f
--- /dev/null
+++ b/Web/Presenters/ImagesProxyPresenter.php
@@ -0,0 +1,63 @@
+image("image/png", strlen($placeholder), $placeholder);
+ }
+
+ public function renderIndex(): void
+ {
+ $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();
+ }
+
+ $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:
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: