[CORE][GSFile] Respect mimetype whitelist and extensions blacklist before saving files
This commit is contained in:
parent
b7d9da8ae6
commit
bccafd0d7b
@ -24,6 +24,7 @@ declare(strict_types = 1);
|
|||||||
namespace App\Core;
|
namespace App\Core;
|
||||||
|
|
||||||
use App\Core\DB\DB;
|
use App\Core\DB\DB;
|
||||||
|
use App\Util\Exception\FileNotAllowedException;
|
||||||
use function App\Core\I18n\_m;
|
use function App\Core\I18n\_m;
|
||||||
use App\Entity\Attachment;
|
use App\Entity\Attachment;
|
||||||
use App\Util\Common;
|
use App\Util\Common;
|
||||||
@ -92,14 +93,19 @@ class GSFile
|
|||||||
$attachment->setWidth($width);
|
$attachment->setWidth($width);
|
||||||
$attachment->setHeight($height);
|
$attachment->setHeight($height);
|
||||||
$attachment->setSize($file->getSize());
|
$attachment->setSize($file->getSize());
|
||||||
$file->move(Common::config('attachments', 'dir'), $hash);
|
if (self::isMimetypeAllowed($mimetype)) {
|
||||||
|
$file->move(Common::config('attachments', 'dir'), $hash);
|
||||||
|
DB::persist($attachment);
|
||||||
|
} else {
|
||||||
|
throw new FileNotAllowedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (NotFoundException) {
|
} catch (NotFoundException) {
|
||||||
// Create an Attachment
|
// Create an Attachment
|
||||||
// The following properly gets the mimetype with `file` or other
|
// The following properly gets the mimetype with `file` or other
|
||||||
// available methods, so should be safe
|
// available methods, so should be safe
|
||||||
$mimetype = mb_substr($file->getMimeType(), 0, 64);
|
$mimetype = mb_substr($file->getMimeType(), 0, 64);
|
||||||
$width = $height = null;
|
$width = $height = null;
|
||||||
$event_map[$mimetype] = [];
|
$event_map[$mimetype] = [];
|
||||||
$major_mime = self::mimetypeMajor($mimetype);
|
$major_mime = self::mimetypeMajor($mimetype);
|
||||||
$event_map[$major_mime] = [];
|
$event_map[$major_mime] = [];
|
||||||
@ -123,13 +129,37 @@ class GSFile
|
|||||||
'width' => $width,
|
'width' => $width,
|
||||||
'height' => $height,
|
'height' => $height,
|
||||||
]);
|
]);
|
||||||
$file->move(Common::config('attachments', 'dir'), $hash);
|
if (self::isMimetypeAllowed($mimetype)) {
|
||||||
DB::persist($attachment);
|
$file->move(Common::config('attachments', 'dir'), $hash);
|
||||||
|
DB::persist($attachment);
|
||||||
|
} else {
|
||||||
|
$attachment->setFilename(null);
|
||||||
|
$attachment->setMimetype(null);
|
||||||
|
$attachment->setSize(null);
|
||||||
|
$attachment->setWidth(null);
|
||||||
|
$attachment->setHeight(null);
|
||||||
|
DB::persist($attachment);
|
||||||
|
throw new FileNotAllowedException($mimetype);
|
||||||
|
}
|
||||||
Event::handle('AttachmentStoreNew', [&$attachment]);
|
Event::handle('AttachmentStoreNew', [&$attachment]);
|
||||||
}
|
}
|
||||||
return $attachment;
|
return $attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests against common config attachment `supported` mimetypes and `ext_blacklist`.
|
||||||
|
*
|
||||||
|
* @param string $mimetype
|
||||||
|
* @return bool true if allowed, false otherwise
|
||||||
|
*/
|
||||||
|
public static function isMimetypeAllowed(string $mimetype): bool {
|
||||||
|
$passed_whitelist = in_array($mimetype, array_keys(Common::config('attachments', 'supported')));
|
||||||
|
$mime = new MimeTypes();
|
||||||
|
$passed_blacklist = count(array_intersect($mime->getExtensions($mimetype), Common::config('attachments', 'ext_blacklist'))) === 0;
|
||||||
|
unset($mime);
|
||||||
|
return $passed_whitelist && $passed_blacklist;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Include $filepath in the response, for viewing or downloading.
|
* Include $filepath in the response, for viewing or downloading.
|
||||||
*
|
*
|
||||||
|
30
src/Util/Exception/FileNotAllowedException.php
Normal file
30
src/Util/Exception/FileNotAllowedException.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
// {{{ License
|
||||||
|
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||||
|
//
|
||||||
|
// GNU social is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// GNU social is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
namespace App\Util\Exception;
|
||||||
|
|
||||||
|
class FileNotAllowedException extends \InvalidArgumentException
|
||||||
|
{
|
||||||
|
public function __construct(string $mimetype)
|
||||||
|
{
|
||||||
|
parent::__construct("File mimetype not allowed: '{$mimetype}'.");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user