Add whitelist back in and validate extension of file is permtted for the mime-type...
authorSeamus Lee <seamuslee001@gmail.com>
Fri, 3 May 2019 04:53:48 +0000 (14:53 +1000)
committerSeamus Lee <seamuslee001@gmail.com>
Tue, 14 May 2019 21:44:41 +0000 (07:44 +1000)
Switch to different libary that is php5.6 compatable

CRM/Core/Page/File.php
CRM/Utils/File.php
composer.json
composer.lock
settings/Core.setting.php
tests/phpunit/CRM/Utils/FileTest.php

index 57ffc9b8ec5db76c77335ea6dabb8e697b1a100a..e32f90f79f3bb0c12c8cd2a92a4fc5530ae5f46d 100644 (file)
@@ -68,22 +68,22 @@ class CRM_Core_Page_File extends CRM_Core_Page {
       $mimeType = '';
       $path = CRM_Core_Config::singleton()->customFileUploadDir . $fileName;
     }
-    $passedInMimeType = CRM_Utils_Request::retrieveValue('mime-type', 'String', $mimeType, FALSE);
 
     if (!$path) {
       CRM_Core_Error::statusBounce('Could not retrieve the file');
     }
-    if (!empty($mimeType) && !empty($passedInMimeType)) {
-      if ($passedInMimeType != $mimeType) {
-        throw new CRM_Core_Exception("Supplied Mime Type does not match file Mime Type");
+
+    if (empty($mimeType)) {
+      $passedInMimeType = CRM_Utils_Request::retrieveValue('mime-type', 'String', $mimeType, FALSE);
+      if (!in_array($passedInMimeType, explode(',', Civi::settings()->get('requestableMimeTypes')))) {
+        throw new CRM_Core_Exception("Supplied mime-type is not accepted");
       }
-    }
-    elseif (!empty($passedInMimeType)) {
-      $testMimeType = CRM_Utils_File::getMimeType($path);
-      if ($testMimeType != $passedInMimeType) {
-        throw new CRM_Core_Exception("Supplied Mime Type does not match file Mime Type");
+      $extension = CRM_Utils_File::getExtensionFromPath($path);
+      $candidateExtensions = CRM_Utils_File::getAcceptableExtensionsForMimeType($passedInMimeType);
+      if (!in_array($extension, $candidateExtensions)) {
+        throw new CRM_Core_Exception("Supplied mime-type does not match file extension");
       }
-      // Now that we have ensured that the mime-type matches to what we believe is the mime-type of the file
+      // Now that we have validated mime-type supplied as much as possible lets now set the MimeType variable/
       $mimeType = $passedInMimeType;
     }
 
index cf3a277bb44144005b15153546c838656244e6b7..efd0b79c6141a4e279011617bbc0ebcbf1840949 100644 (file)
@@ -1067,12 +1067,28 @@ HTACCESS;
   }
 
   /**
-   * Get the Mime-Type of a file based on the url path
-   * @param string $path full filename path
-   * @return string|bool
+   * Get the extensions that this MimeTpe is for
+   * @param string $mimeType the mime-type we want extensions for
+   * @return array
+   */
+  public static function getAcceptableExtensionsForMimeType($mimeType = NULL) {
+    $mapping = \MimeType\Mapping::$types;
+    $extensions = [];
+    foreach ($mapping as $extension => $type) {
+      if ($mimeType == $type) {
+        $extensions[] = $extension;
+      }
+    }
+    return $extensions;
+  }
+
+  /**
+   * Get the extension of a file based on its path
+   * @param string $path path of the file to query
+   * @return string
    */
-  public function getMimeType($path = NULL) {
-    return mime_content_type($path);
+  public static function getExtensionFromPath($path) {
+    return pathinfo($path, PATHINFO_EXTENSION);
   }
 
 }
index fb0a9154945ff3c3c0388a21c8235ce3b9b5dede..bdbf553c4a607c5dc91284cdd18305cf9087f75b 100644 (file)
@@ -61,7 +61,8 @@
     "psr/simple-cache": "~1.0.1",
     "cweagans/composer-patches": "~1.0",
     "pear/log": "1.13.1",
-    "ezyang/htmlpurifier": "4.10"
+    "ezyang/htmlpurifier": "4.10",
+    "katzien/php-mime-type": "2.1.0"
   },
   "scripts": {
     "post-install-cmd": [
index c8c7a6559654e649b056a3bd67da28094553bf2d..b0f5e5e881cfd82c6579e431b0efff75f577ec01 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "93a9f686f7eb00fb9d766d262eedb09b",
+    "content-hash": "2a06373b9174ae3aa2bfb820e2e5a35e",
     "packages": [
         {
             "name": "civicrm/civicrm-cxn-rpc",
             ],
             "time": "2017-03-20T17:10:46+00:00"
         },
+        {
+            "name": "katzien/php-mime-type",
+            "version": "2.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/katzien/PhpMimeType.git",
+                "reference": "159dfbdcd5906442f3dad89951127f0b9dfa3b78"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/katzien/PhpMimeType/zipball/159dfbdcd5906442f3dad89951127f0b9dfa3b78",
+                "reference": "159dfbdcd5906442f3dad89951127f0b9dfa3b78",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "5.*",
+                "satooshi/php-coveralls": "1.*"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "MimeType\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Kat Zien"
+                }
+            ],
+            "description": "A PHP library to detect the mime type of files.",
+            "homepage": "https://github.com/katzien/PhpMimeType",
+            "keywords": [
+                "mimetype",
+                "php"
+            ],
+            "time": "2017-03-23T02:05:33+00:00"
+        },
         {
             "name": "marcj/topsort",
             "version": "1.1.0",
index 27af8a8f5b4f1618f3c17f03248827ad6c64ecfa..cc69e3f982d74b048f47882b5170dfc3efda1522 100644 (file)
@@ -1052,4 +1052,18 @@ return [
     'help_text' => NULL,
     'validate_callback' => 'CRM_Utils_Rule::color',
   ],
+  'requestableMimeTypes' => [
+    'group_name' => 'CiviCRM Preferences',
+    'group' => 'core',
+    'name' => 'requestableMimeTypes',
+    'type' => 'String',
+    'html_type' => 'Text',
+    'default' => 'image/jpeg,image/pjpeg,image/gif,image/x-png,image/png,image/jpg,text/html,application/pdf',
+    'add' => '5.13',
+    'title' => ts('Mime Types that can be passed as URL params'),
+    'is_domain' => 1,
+    'is_contact' => 0,
+    'description' => ts('Acceptable Mime Types that can be used as part of file urls'),
+    'help_text' => NULL,
+  ],
 ];
index f52784ae4fb226c7591ac287c6018b33c7be91c6..3d5c6a0a69623887e5ad7a05eb9e21e4a943ed0a 100644 (file)
@@ -95,4 +95,39 @@ class CRM_Utils_FileTest extends CiviUnitTestCase {
     $this->assertEquals($expectedResult, CRM_Utils_File::isValidFileName($fileName));
   }
 
+  public function pathToFileExtension() {
+    $cases = [];
+    $cases[] = ['/evil.pdf', 'pdf'];
+    $cases[] = ['/helloworld.jpg', 'jpg'];
+    $cases[] = ['/smartwatch_1736683_1280_9af3657015e8660cc234eb1601da871.jpg', 'jpg'];
+    return $cases;
+  }
+
+  /**
+   * Test returning appropriate file extension
+   * @dataProvider pathToFileExtension
+   * @param string $path
+   * @param string $expectedExtension
+   */
+  public function testPathToExtension($path, $expectedExtension) {
+    $this->assertEquals($expectedExtension, CRM_Utils_File::getExtensionFromPath($path));
+  }
+
+  public function mimeTypeToExtension() {
+    $cases = [];
+    $cases[] = ['text/plain', ['txt', 'text', 'conf', 'def', 'list', 'log', 'in']];
+    $cases[] = ['image/jpeg', ['jpeg','jpg', 'jpe']];
+    $cases[] = ['image/png', ['png']];
+    return $cases;
+  }
+
+  /**
+   * @dataProvider mimeTypeToExtension
+   * @param stirng $mimeType
+   * @param array $expectedExtensions
+   */
+  public function testMimeTypeToExtension($mimeType, $expectedExtensions) {
+    $this->assertEquals($expectedExtensions, CRM_Utils_File::getAcceptableExtensionsForMimeType($mimeType));
+  }
+
 }