Make uploads work properly if we accept _all_ attachment types

Also introduced $config['attachments']['extblacklist'] that can disable
certain file extensions (or rewrite them, for example php => phps)
This commit is contained in:
Mikael Nordfeldth 2016-02-25 22:15:54 +01:00
parent 28d9f82ab1
commit e6e1705852
3 changed files with 50 additions and 11 deletions

View File

@ -237,7 +237,7 @@ class File extends Managed_DataObject
static function filename(Profile $profile, $origname, $mimetype) static function filename(Profile $profile, $origname, $mimetype)
{ {
$ext = self::guessMimeExtension($mimetype); $ext = self::guessMimeExtension($mimetype, $origname);
// Normalize and make the original filename more URL friendly. // Normalize and make the original filename more URL friendly.
$origname = basename($origname, ".$ext"); $origname = basename($origname, ".$ext");
@ -258,19 +258,54 @@ class File extends Managed_DataObject
return $filename; return $filename;
} }
static function guessMimeExtension($mimetype) /**
* @param $mimetype The mimetype we've discovered for this file.
* @param $filename An optional filename which we can use on failure.
*/
static function guessMimeExtension($mimetype, $filename=null)
{ {
$ext = null;
try { try {
// first see if we know the extension for our mimetype
$ext = common_supported_mime_to_ext($mimetype); $ext = common_supported_mime_to_ext($mimetype);
} catch (Exception $e) { // we do, so use it!
// We don't support this mimetype, but let's guess the extension return $ext;
$matches = array(); } catch (Exception $e) { // FIXME: Make this exception more specific to "unknown mime=>ext relation"
if (!preg_match('/\/([a-z0-9]+)/', mb_strtolower($mimetype), $matches)) { // We don't know the extension for this mimetype, but let's guess.
throw new Exception('Malformed mimetype: '.$mimetype);
// If we are very liberal with uploads ($config['attachments']['supported'] === true)
// then we try to do some guessing based on the filename, if it was supplied.
if (!is_null($filename) && common_config('attachments', 'supported')===true
&& preg_match('/^.+\.([A-Za-z0-9]+)$/', $filename, $matches)) {
// we matched on a file extension, so let's see if it means something.
$ext = mb_strtolower($matches[1]);
$blacklist = common_config('attachments', 'extblacklist');
// If we got an extension from $filename we want to check if it's in a blacklist
// so we avoid people uploading .php files etc.
if (array_key_exists($ext, $blacklist)) {
if (!is_string($blacklist[$ext])) {
// we don't have a safe replacement extension
throw ClientException(_('Blacklisted file extension.'));
}
common_debug('Found replaced extension for filename '._ve($filename).': '._ve($ext));
// return a safe replacement extension ('php' => 'phps' for example)
return $blacklist[$ext];
}
// the attachment extension based on its filename was not blacklisted so it's ok to use it
return $ext;
} }
$ext = $matches[1];
} }
return mb_strtolower($ext);
// If nothing else has given us a result, try to extract it from
// the mimetype value (this turns .jpg to .jpeg for example...)
$matches = array();
if (!preg_match('/\/([a-z0-9]+)/', mb_strtolower($mimetype), $matches)) {
throw new Exception('Malformed mimetype: '.$mimetype);
}
$ext = mb_strtolower($matches[1]);
return $ext;
} }
/** /**

View File

@ -266,6 +266,10 @@ $default =
'show_html' => false, // show (filtered) text/html attachments (and oEmbed HTML etc.). Doesn't affect AJAX calls. 'show_html' => false, // show (filtered) text/html attachments (and oEmbed HTML etc.). Doesn't affect AJAX calls.
'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info 'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info
'process_links' => true, // check linked resources for embeddable photos and videos; this will hit referenced external web sites when processing new messages. 'process_links' => true, // check linked resources for embeddable photos and videos; this will hit referenced external web sites when processing new messages.
'extblacklist' => [
'php' => 'phps',
'exe' => false, // this would deny any uploads to keep the "exe" file extension
],
), ),
'thumbnail' => 'thumbnail' =>
array('crop' => false, // overridden to true if thumb height === null array('crop' => false, // overridden to true if thumb height === null

View File

@ -253,15 +253,15 @@ class MediaFile
File::respectsQuota($scoped, $_FILES[$param]['size']); File::respectsQuota($scoped, $_FILES[$param]['size']);
$mimetype = self::getUploadedMimeType($_FILES[$param]['tmp_name'], $_FILES[$param]['name']); $mimetype = self::getUploadedMimeType($_FILES[$param]['tmp_name'], $_FILES[$param]['name']);
$basename = basename($_FILES[$param]['name']);
switch (common_config('attachments', 'filename_base')) { switch (common_config('attachments', 'filename_base')) {
case 'upload': case 'upload':
$basename = basename($_FILES[$param]['name']);
$filename = File::filename($scoped, $basename, $mimetype); $filename = File::filename($scoped, $basename, $mimetype);
break; break;
case 'hash': case 'hash':
default: default:
$filename = strtolower($filehash) . '.' . File::guessMimeExtension($mimetype); $filename = strtolower($filehash) . '.' . File::guessMimeExtension($mimetype, $basename);
} }
$filepath = File::path($filename); $filepath = File::path($filename);