generateFileHash() and validateFileHash() should be colocated
[civicrm-core.git] / CRM / Core / BAO / File.php
index e0f4b2fa279922a576dfdff4cd721647a381830d..4468dd8c0f2da465d58767675902703c09170074 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 5                                                  |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2018                                |
+ | Copyright CiviCRM LLC (c) 2004-2019                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
@@ -28,7 +28,7 @@
 /**
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2018
+ * @copyright CiviCRM LLC (c) 2004-2019
  * $Id$
  *
  */
@@ -71,15 +71,11 @@ class CRM_Core_BAO_File extends CRM_Core_DAO_File {
   /**
    * @param int $fileID
    * @param int $entityID
-   * @param null $entityTable
    *
    * @return array
    */
-  public static function path($fileID, $entityID, $entityTable = NULL) {
+  public static function path($fileID, $entityID) {
     $entityFileDAO = new CRM_Core_DAO_EntityFile();
-    if ($entityTable) {
-      $entityFileDAO->entity_table = $entityTable;
-    }
     $entityFileDAO->entity_id = $entityID;
     $entityFileDAO->file_id = $fileID;
 
@@ -337,6 +333,7 @@ class CRM_Core_BAO_File extends CRM_Core_DAO_File {
     $dao = CRM_Core_DAO::executeQuery($sql, $params);
     $results = array();
     while ($dao->fetch()) {
+      $fileHash = self::generateFileHash($dao->entity_id, $dao->cfID);
       $result['fileID'] = $dao->cfID;
       $result['entityID'] = $dao->cefID;
       $result['mime_type'] = $dao->mime_type;
@@ -344,7 +341,7 @@ class CRM_Core_BAO_File extends CRM_Core_DAO_File {
       $result['description'] = $dao->description;
       $result['cleanName'] = CRM_Utils_File::cleanFileName($dao->uri);
       $result['fullPath'] = $config->customFileUploadDir . DIRECTORY_SEPARATOR . $dao->uri;
-      $result['url'] = CRM_Utils_System::url('civicrm/file', "reset=1&id={$dao->cfID}&eid={$dao->entity_id}");
+      $result['url'] = CRM_Utils_System::url('civicrm/file', "reset=1&id={$dao->cfID}&eid={$dao->entity_id}&fcs={$fileHash}");
       $result['href'] = "<a href=\"{$result['url']}\">{$result['cleanName']}</a>";
       $result['tag'] = CRM_Core_BAO_EntityTag::getTag($dao->cfID, 'civicrm_file');
       $result['icon'] = CRM_Utils_File::getIconFromMimeType($dao->mime_type);
@@ -770,4 +767,50 @@ AND       CEF.entity_id    = %2";
     return NULL;
   }
 
+  /**
+   * Generates a MD5 Hash to be appended to file URLS to be checked when trying to download the file.
+   * @param int $eid entity id the file is attached to
+   * @param int $fid file ID
+   * @return string
+   */
+  public static function generateFileHash($eid = NULL, $fid = NULL, $genTs = NULL, $life = NULL) {
+    // Use multiple (but stable) inputs for hash information.
+    $siteKey = defined('CIVICRM_SITE_KEY') ? CIVICRM_SITE_KEY : 'NO_SITE_KEY';
+
+    if (!$genTs) {
+      $genTs = time();
+    }
+    if (!$life) {
+      $life = 24 * 2;
+    }
+    // Trim 8 chars off the string, make it slightly easier to find
+    // but reveals less information from the hash.
+    $cs = hash_hmac('sha256', "{$fid}_{$life}", $siteKey);
+    return "{$cs}_{$genTs}_{$life}";
+  }
+
+  /**
+   * Validate a file Hash
+   * @param string $hash
+   * @param int $eid Entity Id the file is attached to
+   * @param int $fid File Id
+   * @return bool
+   */
+  public static function validateFileHash($hash, $eid, $fid) {
+    $input = CRM_Utils_System::explode('_', $hash, 3);
+    $inputTs = CRM_Utils_Array::value(1, $input);
+    $inputLF = CRM_Utils_Array::value(2, $input);
+    $testHash = CRM_Core_BAO_File::generateFileHash($eid, $fid, $inputTs, $inputLF);
+    if (hash_equals($testHash, $hash)) {
+      $now = time();
+      if ($inputTs + ($inputLF * 60 * 60) >= $now) {
+        return TRUE;
+      }
+      else {
+        return FALSE;
+      }
+    }
+    return FALSE;
+  }
+
 }