Add media proxying.
This commit is contained in:
parent
3f244cfc53
commit
4fe3c6644d
6 changed files with 117 additions and 10 deletions
|
@ -43,3 +43,10 @@ method = null
|
||||||
[Exceptions]
|
[Exceptions]
|
||||||
report_url = http://misuzu-crash.localhost/report.php
|
report_url = http://misuzu-crash.localhost/report.php
|
||||||
hash_key = secret_key_used_to_make_a_hmac_sha256_hash
|
hash_key = secret_key_used_to_make_a_hmac_sha256_hash
|
||||||
|
|
||||||
|
[CSRF]
|
||||||
|
secret_key = secret_key_for_generating_csrf_tokens
|
||||||
|
|
||||||
|
[Proxy]
|
||||||
|
enabled = true
|
||||||
|
secret_key = change_this_or_i_will_beat_you_up
|
||||||
|
|
81
public/proxy.php
Normal file
81
public/proxy.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
require_once '../misuzu.php';
|
||||||
|
|
||||||
|
$acceptedProtocols = ['http', 'https'];
|
||||||
|
$acceptedMimeTypes = [
|
||||||
|
'image/png', 'image/jpeg', 'image/bmp', 'image/gif', 'image/svg', 'image/svg+xml', 'image/tiff', 'image/webp',
|
||||||
|
'video/mp4', 'video/webm', 'video/x-msvideo', 'video/mpeg', 'video/ogg',
|
||||||
|
];
|
||||||
|
|
||||||
|
header('Cache-Control: max-age=600');
|
||||||
|
|
||||||
|
if (!empty($_GET['t'])) {
|
||||||
|
$_hash = hash_hmac('sha256', $_GET['t'], $proxySecret);
|
||||||
|
$_url = rawurlencode($_GET['t']);
|
||||||
|
header("Location: /proxy.php?u={$_url}&h={$_hash}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$proxyUrl = rawurldecode($_GET['u'] ?? '');
|
||||||
|
$proxyHash = $_GET['h'] ?? '';
|
||||||
|
|
||||||
|
if (empty($proxyHash) || empty($proxyUrl)) {
|
||||||
|
echo render_error(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsedUrl = parse_url($proxyUrl);
|
||||||
|
|
||||||
|
if (empty($parsedUrl['scheme'])
|
||||||
|
|| empty($parsedUrl['host'])
|
||||||
|
|| !in_array($parsedUrl['scheme'], $acceptedProtocols, true)) {
|
||||||
|
echo render_error(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config_get_default(false, 'Proxy', 'enabled')) {
|
||||||
|
header('Location: ' . $proxyUrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$proxySecret = config_get_default('insecure', 'Proxy', 'secret_key');
|
||||||
|
$expectedHash = hash_hmac('sha256', $proxyUrl, $proxySecret);
|
||||||
|
|
||||||
|
if (!hash_equals($expectedHash, $proxyHash)) {
|
||||||
|
echo render_error(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$curl = curl_init($proxyUrl);
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_CERTINFO => false,
|
||||||
|
CURLOPT_FAILONERROR => false,
|
||||||
|
CURLOPT_FOLLOWLOCATION => true,
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_TCP_FASTOPEN => true,
|
||||||
|
CURLOPT_CONNECTTIMEOUT => 2,
|
||||||
|
CURLOPT_MAXREDIRS => 4,
|
||||||
|
CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,
|
||||||
|
CURLOPT_TIMEOUT => 10,
|
||||||
|
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible) Misuzu/' . git_tag(),
|
||||||
|
]);
|
||||||
|
$curlBody = curl_exec($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
|
$fileMime = finfo_buffer($finfo, $curlBody);
|
||||||
|
finfo_close($finfo);
|
||||||
|
|
||||||
|
if (!in_array($fileMime, $acceptedMimeTypes, true)) {
|
||||||
|
echo render_error(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileSize = strlen($curlBody);
|
||||||
|
$fileName = basename($parsedUrl['path'] ?? "proxied-image-{$expectedHash}");
|
||||||
|
|
||||||
|
header("Content-Type: {$fileMime}");
|
||||||
|
header("Content-Length: {$fileSize}");
|
||||||
|
header("Content-Disposition: inline; filename=\"{$fileName}\"");
|
||||||
|
|
||||||
|
echo $curlBody;
|
|
@ -1,17 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Parsers\BBCode\Tags;
|
namespace Misuzu\Parsers\BBCode\Tags;
|
||||||
|
|
||||||
use Misuzu\Parsers\BBCode\BBCodeSimpleTag;
|
use Misuzu\Parsers\BBCode\BBCodeTag;
|
||||||
|
|
||||||
final class ImageTag extends BBCodeSimpleTag
|
final class ImageTag extends BBCodeTag
|
||||||
{
|
{
|
||||||
public function getPattern(): string
|
public function parseText(string $text): string
|
||||||
{
|
{
|
||||||
return "/\[img\]((?:https?:\/\/).*)\[\/img\]/";
|
return preg_replace_callback("/\[img\]((?:https?:\/\/).*)\[\/img\]/", function ($matches) {
|
||||||
}
|
$mediaUrl = proxy_media_url($matches[1]);
|
||||||
|
return sprintf('<img src="%s" alt="%s" style="max-width:100%%;max-height:100%%;">', $mediaUrl, $matches[1]);
|
||||||
public function getReplacement(): string
|
}, $text);
|
||||||
{
|
|
||||||
return '<img src="$1" alt="$1" style="max-width:100%;max-height:100%;">';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ final class VideoTag extends BBCodeTag
|
||||||
. '?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>';
|
. '?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return "<video controls src='{$matches[1]}'></video>";
|
$mediaUrl = proxy_media_url($matches[1]);
|
||||||
|
return "<video controls src='{$mediaUrl}'></video>";
|
||||||
},
|
},
|
||||||
$text
|
$text
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,4 +14,11 @@ class MarkdownParser extends Parsedown implements ParserInterface
|
||||||
{
|
{
|
||||||
return $this->line($line);
|
return $this->line($line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function inlineImage($excerpt)
|
||||||
|
{
|
||||||
|
$object = parent::inlineImage($excerpt);
|
||||||
|
$object['element']['attributes']['src'] = proxy_media_url($object['element']['attributes']['src']);
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
13
utility.php
13
utility.php
|
@ -346,3 +346,16 @@ function is_user_int($value): bool
|
||||||
{
|
{
|
||||||
return ctype_digit(strval($value));
|
return ctype_digit(strval($value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function proxy_media_url(string $url): string
|
||||||
|
{
|
||||||
|
if (!config_get_default(false, 'Proxy', 'enabled') || is_local_url($url)) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$secret = config_get_default('insecure', 'Proxy', 'secret_key');
|
||||||
|
$hash = hash_hmac('sha256', $url, $secret);
|
||||||
|
$encodedUrl = rawurlencode($url);
|
||||||
|
|
||||||
|
return "/proxy.php?h={$hash}&u={$encodedUrl}";
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue