From 020f477e0a6a324f2c8ec4c28f5b178ab833a317 Mon Sep 17 00:00:00 2001
From: Uma <uma.s@vtiger.com>
Date: Fri, 30 Aug 2019 17:20:16 +0530
Subject: [PATCH] File security through obscurity is supported

---
 data/CRMEntity.php                            | 15 ++--
 .../Contacts/DetailViewHeaderTitle.tpl        |  4 +-
 .../Products/DetailViewHeaderTitle.tpl        | 10 +--
 .../Users/CalendarSettingsDetailView.tpl      |  4 +-
 .../v7/modules/Users/DetailViewBlockView.tpl  |  4 +-
 layouts/v7/modules/Users/ListViewContents.tpl |  4 +-
 .../Users/PreferenceDetailViewHeader.tpl      |  4 +-
 layouts/v7/modules/Users/UserViewHeader.tpl   |  4 +-
 .../v7/modules/Vtiger/DetailViewBlockView.tpl |  4 +-
 modules/Documents/models/Record.php           |  2 +-
 modules/Documents/views/FilePreview.php       |  2 +-
 modules/Emails/actions/DownloadFile.php       |  2 +-
 modules/Products/models/Record.php            |  7 +-
 modules/Users/Users.php                       |  2 +-
 modules/Users/models/Record.php               |  5 +-
 modules/Vtiger/helpers/ShowFile.php           | 69 +++++++++++++++++++
 modules/Vtiger/helpers/Util.php               | 10 +++
 modules/Vtiger/models/Record.php              |  8 ++-
 .../modules/ModComments/views/FilePreview.php |  2 +-
 public.php                                    | 15 ++++
 vtlib/Vtiger/Functions.php                    | 16 +++++
 21 files changed, 155 insertions(+), 38 deletions(-)
 create mode 100644 modules/Vtiger/helpers/ShowFile.php
 create mode 100644 public.php

diff --git a/data/CRMEntity.php b/data/CRMEntity.php
index e36c9cda0..64650430e 100644
--- a/data/CRMEntity.php
+++ b/data/CRMEntity.php
@@ -186,20 +186,17 @@ class CRMEntity {
 		if ($save_file == 'false') {
 			return false;
 		}
-        
-        $binFile = sanitizeUploadFileName($file_name, $upload_badext);
-
-		$current_id = $adb->getUniqueID("vtiger_crmentity");
 
 		// Check 2
 		$save_file = 'true';
 		//only images are allowed for these modules
 		if ($module == 'Contacts' || $module == 'Products') {
 			$save_file = validateImageFile($file_details);
-            $serverFileName = $current_id . "_" . $binFile;
-		} else {
-            $serverFileName = md5($current_id . "_" . $binFile);
-        }
+		}
+
+		$binFile = sanitizeUploadFileName($file_name, $upload_badext);
+
+		$current_id = $adb->getUniqueID("vtiger_crmentity");
 
 		$filename = ltrim(basename(" " . $binFile)); //allowed filename like UTF-8 characters
 		$filetype = $file_details['type'];
@@ -209,7 +206,7 @@ class CRMEntity {
 		$upload_file_path = decideFilePath();
 
 		// upload the file in server
-		$upload_status = copy($filetmp_name, $upload_file_path . $serverFileName);
+		$upload_status = copy($filetmp_name, $upload_file_path . $current_id . "_" . Vtiger_Util_Helper::getEncryptedFileName($binFile));
 		// temporary file will be deleted at the end of request
 
 		if ($save_file == 'true' && $upload_status == 'true') {
diff --git a/layouts/v7/modules/Contacts/DetailViewHeaderTitle.tpl b/layouts/v7/modules/Contacts/DetailViewHeaderTitle.tpl
index 321a15830..be2ec4552 100644
--- a/layouts/v7/modules/Contacts/DetailViewHeaderTitle.tpl
+++ b/layouts/v7/modules/Contacts/DetailViewHeaderTitle.tpl
@@ -15,8 +15,8 @@
 		 <div class="hidden-sm hidden-xs recordImage bgcontacts app-{$SELECTED_MENU_CATEGORY}">
 			{assign var=IMAGE_DETAILS value=$RECORD->getImageDetails()}
 			{foreach key=ITER item=IMAGE_INFO from=$IMAGE_DETAILS}
-			   {if !empty($IMAGE_INFO.path)}
-				  <img src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" width="100%" height="100%" align="left"><br>
+			   {if !empty($IMAGE_INFO.url)}
+				  <img src="{$IMAGE_INFO.url}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" width="100%" height="100%" align="left"><br>
 			   {else}
 				  <img src="{vimage_path('summary_Contact.png')}" class="summaryImg"/>
 			   {/if}
diff --git a/layouts/v7/modules/Products/DetailViewHeaderTitle.tpl b/layouts/v7/modules/Products/DetailViewHeaderTitle.tpl
index 59f83579e..0dc6610d4 100644
--- a/layouts/v7/modules/Products/DetailViewHeaderTitle.tpl
+++ b/layouts/v7/modules/Products/DetailViewHeaderTitle.tpl
@@ -15,16 +15,16 @@
                 {assign var=IMAGE_DETAILS value=$RECORD->getImageDetails()}
             <div class="hidden-sm hidden-xs recordImage bgproducts app-{$SELECTED_MENU_CATEGORY}" {if $IMAGE_DETAILS|@count gt 1}style = "display:block"{/if}>
                 {foreach key=ITER item=IMAGE_INFO from=$IMAGE_DETAILS}
-	               {if !empty($IMAGE_INFO.path)}
+	               {if !empty($IMAGE_INFO.url)}
 	                {if $IMAGE_DETAILS|@count eq 1}
-	                    <img src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" width="100%" height="100%" align="left"><br>
+	                    <img src="{$IMAGE_INFO.url}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" width="100%" height="100%" align="left"><br>
 	                {else if $IMAGE_DETAILS|@count eq 2}
-	                    <span><img src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" width="50%" height="100%" align="left"></span>
+	                    <span><img src="{$IMAGE_INFO.url}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" width="50%" height="100%" align="left"></span>
 	                {else if $IMAGE_DETAILS|@count eq 3}
-	                    <span><img src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" {if $ITER eq 0 or $ITER eq 1}width="50%" height = "50%"{/if}{if $ITER eq 2}width="100%" height="50%"{/if} align="left"></span>
+	                    <span><img src="{$IMAGE_INFO.url}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" {if $ITER eq 0 or $ITER eq 1}width="50%" height = "50%"{/if}{if $ITER eq 2}width="100%" height="50%"{/if} align="left"></span>
 	                {else if $IMAGE_DETAILS|@count eq 4 or $IMAGE_DETAILS|@count gt 4}
 	                    {if $ITER gt 3}{break}{/if}
-	                    <span><img src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}"width="50%" height="50%" align="left"></span>
+	                    <span><img src="{$IMAGE_INFO.url}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}"width="50%" height="50%" align="left"></span>
 	                {/if}
 	               {else}
 	                  <img src="{vimage_path('summary_Products.png')}" class="summaryImg"/>
diff --git a/layouts/v7/modules/Users/CalendarSettingsDetailView.tpl b/layouts/v7/modules/Users/CalendarSettingsDetailView.tpl
index 6c327c349..cb37e45d8 100644
--- a/layouts/v7/modules/Users/CalendarSettingsDetailView.tpl
+++ b/layouts/v7/modules/Users/CalendarSettingsDetailView.tpl
@@ -72,8 +72,8 @@
                                         <td class="fieldValue {$WIDTHTYPE}">
                                             <div id="imageContainer" width="300" height="200">
                                                 {foreach key=ITER item=IMAGE_INFO from=$IMAGE_DETAILS}
-                                                    {if !empty($IMAGE_INFO.path) && !empty({$IMAGE_INFO.orgname})}
-                                                        <img src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" width="300" height="200">
+                                                    {if !empty($IMAGE_INFO.url) && !empty({$IMAGE_INFO.orgname})}
+                                                        <img src="{$IMAGE_INFO.url}" width="300" height="200">
                                                     {/if}
                                                 {/foreach}
                                             </div>
diff --git a/layouts/v7/modules/Users/DetailViewBlockView.tpl b/layouts/v7/modules/Users/DetailViewBlockView.tpl
index 0d4cd57c6..50b41e2dc 100644
--- a/layouts/v7/modules/Users/DetailViewBlockView.tpl
+++ b/layouts/v7/modules/Users/DetailViewBlockView.tpl
@@ -65,8 +65,8 @@
 										<td class="fieldValue {$WIDTHTYPE}">
 											<div id="imageContainer" width="300" height="200">
 												{foreach key=ITER item=IMAGE_INFO from=$IMAGE_DETAILS}
-													{if !empty($IMAGE_INFO.path) && !empty({$IMAGE_INFO.orgname})}
-														<img src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" width="300" height="200">
+													{if !empty($IMAGE_INFO.url) && !empty({$IMAGE_INFO.orgname})}
+														<img src="{$IMAGE_INFO.url}" width="300" height="200">
 													{/if}
 												{/foreach}
 											</div>
diff --git a/layouts/v7/modules/Users/ListViewContents.tpl b/layouts/v7/modules/Users/ListViewContents.tpl
index d0e37a725..4c505bde7 100644
--- a/layouts/v7/modules/Users/ListViewContents.tpl
+++ b/layouts/v7/modules/Users/ListViewContents.tpl
@@ -97,9 +97,9 @@
 												<div style="margin-left: -13px;">
 													{assign var=IMAGE_DETAILS value=$LISTVIEW_ENTRY->getImageDetails()}
 													{foreach item=IMAGE_INFO from=$IMAGE_DETAILS}
-														{if !empty($IMAGE_INFO.path) && !empty({$IMAGE_INFO.orgname})}
+														{if !empty($IMAGE_INFO.url) && !empty({$IMAGE_INFO.orgname})}
 															<div class='col-lg-2'>
-																<img height="25px" width="25px" src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}">
+																<img height="25px" width="25px" src="{$IMAGE_INFO.url}">
 															</div>
 														{/if}
 													{/foreach}
diff --git a/layouts/v7/modules/Users/PreferenceDetailViewHeader.tpl b/layouts/v7/modules/Users/PreferenceDetailViewHeader.tpl
index 10b30b2c5..3c6173ce5 100644
--- a/layouts/v7/modules/Users/PreferenceDetailViewHeader.tpl
+++ b/layouts/v7/modules/Users/PreferenceDetailViewHeader.tpl
@@ -18,9 +18,9 @@
 				<div class="col-xs-8">
 					{assign var=IMAGE_DETAILS value=$RECORD->getImageDetails()}
 					{foreach key=ITER item=IMAGE_INFO from=$IMAGE_DETAILS}
-						{if !empty($IMAGE_INFO.path) && !empty($IMAGE_INFO.orgname)}
+						{if !empty($IMAGE_INFO.url) && !empty($IMAGE_INFO.orgname)}
 							<span class="logo col-xs-2">
-								<img height="75px" width="75px" src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" data-image-id="{$IMAGE_INFO.id}">
+								<img height="75px" width="75px" src="{$IMAGE_INFO.url}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" data-image-id="{$IMAGE_INFO.id}">
 							</span>
 						{/if}
 					{/foreach}
diff --git a/layouts/v7/modules/Users/UserViewHeader.tpl b/layouts/v7/modules/Users/UserViewHeader.tpl
index 0aaa035d5..3cef09e74 100644
--- a/layouts/v7/modules/Users/UserViewHeader.tpl
+++ b/layouts/v7/modules/Users/UserViewHeader.tpl
@@ -18,8 +18,8 @@
                     <div class="col-md-5 recordImage" style="height: 50px;width: 50px;">
                         {assign var=NOIMAGE value=0}
                         {foreach key=ITER item=IMAGE_INFO from=$RECORD->getImageDetails()}
-                            {if !empty($IMAGE_INFO.path) && !empty($IMAGE_INFO.orgname)}
-                                <img height="100%" width="100%"src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" data-image-id="{$IMAGE_INFO.id}">
+                            {if !empty($IMAGE_INFO.url) && !empty($IMAGE_INFO.orgname)}
+                                <img height="100%" width="100%"src="{$IMAGE_INFO.url}" alt="{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" data-image-id="{$IMAGE_INFO.id}">
                             {else}
                                 {assign var=NOIMAGE value=1}
                             {/if}
diff --git a/layouts/v7/modules/Vtiger/DetailViewBlockView.tpl b/layouts/v7/modules/Vtiger/DetailViewBlockView.tpl
index 5a47f3518..f2a99adfe 100644
--- a/layouts/v7/modules/Vtiger/DetailViewBlockView.tpl
+++ b/layouts/v7/modules/Vtiger/DetailViewBlockView.tpl
@@ -69,8 +69,8 @@
 									<td class="fieldValue {$WIDTHTYPE}">
 										<ul id="imageContainer">
 											{foreach key=ITER item=IMAGE_INFO from=$IMAGE_DETAILS}
-												{if !empty($IMAGE_INFO.path) && !empty({$IMAGE_INFO.orgname})}
-													<li><img src="{$IMAGE_INFO.path}_{$IMAGE_INFO.orgname}" title="{$IMAGE_INFO.orgname}" width="400" height="300" /></li>
+												{if !empty($IMAGE_INFO.url) && !empty({$IMAGE_INFO.orgname})}
+													<li><img src="{$IMAGE_INFO.url}" title="{$IMAGE_INFO.orgname}" width="400" height="300" /></li>
 												{/if}
 											{/foreach}
 										</ul>
diff --git a/modules/Documents/models/Record.php b/modules/Documents/models/Record.php
index dc876f54c..0fc6b1566 100644
--- a/modules/Documents/models/Record.php
+++ b/modules/Documents/models/Record.php
@@ -75,7 +75,7 @@ class Documents_Record_Model extends Vtiger_Record_Model {
 
 			if ($this->get('filelocationtype') == 'I') {
 				$fileName = html_entity_decode($fileName, ENT_QUOTES, vglobal('default_charset'));
-				$savedFile = md5($fileDetails['attachmentsid']."_".$fileName);
+				$savedFile = $fileDetails['attachmentsid']."_".Vtiger_Util_Helper::getEncryptedFileName($fileName);
 
 				while(ob_get_level()) {
 					ob_end_clean();
diff --git a/modules/Documents/views/FilePreview.php b/modules/Documents/views/FilePreview.php
index 010e1e2b6..884d9f80c 100644
--- a/modules/Documents/views/FilePreview.php
+++ b/modules/Documents/views/FilePreview.php
@@ -44,7 +44,7 @@ class Documents_FilePreview_View extends Vtiger_IndexAjax_View {
 
 			if ($recordModel->get('filelocationtype') == 'I') {
 				$fileName = html_entity_decode($fileName, ENT_QUOTES, vglobal('default_charset'));
-				$savedFile = md5($fileDetails['attachmentsid']."_".$fileName);
+				$savedFile = $fileDetails['attachmentsid']."_".Vtiger_Util_Helper::getEncryptedFileName($fileName);
 
 				$fileSize = filesize($filePath.$savedFile);
 				$fileSize = $fileSize + ($fileSize % 1024);
diff --git a/modules/Emails/actions/DownloadFile.php b/modules/Emails/actions/DownloadFile.php
index f21b6f040..9a85bcfca 100644
--- a/modules/Emails/actions/DownloadFile.php
+++ b/modules/Emails/actions/DownloadFile.php
@@ -34,7 +34,7 @@ class Emails_DownloadFile_Action extends Vtiger_Action_Controller {
             $name = $row["name"];
             $filepath = $row["path"];
             $name = decode_html($name);
-            $saved_filename = md5($attachmentId."_".$name);
+            $saved_filename = $attachmentId."_". Vtiger_Util_Helper::getEncryptedFileName($name);
             $disk_file_size = filesize($filepath.$saved_filename);
             $filesize = $disk_file_size + ($disk_file_size % 1024);
             $fileContent = fread(fopen($filepath.$saved_filename, "r"), $filesize);
diff --git a/modules/Products/models/Record.php b/modules/Products/models/Record.php
index 8fcf1724c..62b58951e 100644
--- a/modules/Products/models/Record.php
+++ b/modules/Products/models/Record.php
@@ -342,6 +342,7 @@ class Products_Record_Model extends Vtiger_Record_Model {
 	 * @return <array> Image Details List
 	 */
 	public function getImageDetails() {
+        global $site_URL;
 		$db = PearDatabase::getInstance();
 		$imageDetails = array();
 		$recordId = $this->getId();
@@ -356,15 +357,18 @@ class Products_Record_Model extends Vtiger_Record_Model {
 			$count = $db->num_rows($result);
 
 			for($i=0; $i<$count; $i++) {
+                $imageId = $db->query_result($result, $i, 'attachmentsid');
 				$imageIdsList[] = $db->query_result($result, $i, 'attachmentsid');
 				$imagePathList[] = $db->query_result($result, $i, 'path');
 				$imageName = $db->query_result($result, $i, 'name');
+                $url = \Vtiger_Functions::getFilePublicURL($imageId, $imageName);
 
 				//decode_html - added to handle UTF-8 characters in file names
 				$imageOriginalNamesList[] = urlencode(decode_html($imageName));
 
 				//urlencode - added to handle special characters like #, %, etc.,
 				$imageNamesList[] = $imageName;
+                $imageUrlsList[] = $url;
 			}
 
 			if(is_array($imageOriginalNamesList)) {
@@ -374,7 +378,8 @@ class Products_Record_Model extends Vtiger_Record_Model {
 							'id' => $imageIdsList[$j],
 							'orgname' => $imageOriginalNamesList[$j],
 							'path' => $imagePathList[$j].$imageIdsList[$j],
-							'name' => $imageNamesList[$j]
+							'name' => $imageNamesList[$j],
+                            'url' => $imageUrlsList[$j]
 					);
 				}
 			}
diff --git a/modules/Users/Users.php b/modules/Users/Users.php
index cf70a282d..bbd76dad3 100755
--- a/modules/Users/Users.php
+++ b/modules/Users/Users.php
@@ -1058,7 +1058,7 @@ class Users extends CRMEntity {
 		//get the file path inwhich folder we want to upload the file
 		$upload_file_path = decideFilePath();
 		//upload the file in server
-		$upload_status = move_uploaded_file($filetmp_name,$upload_file_path.$current_id."_".$binFile);
+		$upload_status = move_uploaded_file($filetmp_name,$upload_file_path.$current_id."_".Vtiger_Util_Helper::getEncryptedFileName($binFile));
 
 		if($save_file == 'true') {
 
diff --git a/modules/Users/models/Record.php b/modules/Users/models/Record.php
index 3c13332b3..c12abc18b 100644
--- a/modules/Users/models/Record.php
+++ b/modules/Users/models/Record.php
@@ -378,6 +378,7 @@ class Users_Record_Model extends Vtiger_Record_Model {
 	 * @return <Array> list of Image names and paths
 	 */
 	public function getImageDetails() {
+        global $site_URL;
 		$db = PearDatabase::getInstance();
 
 		$imageDetails = array();
@@ -394,6 +395,7 @@ class Users_Record_Model extends Vtiger_Record_Model {
 			$imageId = $db->query_result($result, 0, 'attachmentsid');
 			$imagePath = $db->query_result($result, 0, 'path');
 			$imageName = $db->query_result($result, 0, 'name');
+            $url = \Vtiger_Functions::getFilePublicURL($imageId, $imageName);
 
 			//decode_html - added to handle UTF-8 characters in file names
 			$imageOriginalName = urlencode(decode_html($imageName));
@@ -402,7 +404,8 @@ class Users_Record_Model extends Vtiger_Record_Model {
 					'id' => $imageId,
 					'orgname' => $imageOriginalName,
 					'path' => $imagePath.$imageId,
-					'name' => $imageName
+					'name' => $imageName,
+                    'url'  => $site_URL.$url
 			);
 		}
 		return $imageDetails;
diff --git a/modules/Vtiger/helpers/ShowFile.php b/modules/Vtiger/helpers/ShowFile.php
new file mode 100644
index 000000000..c784f57ac
--- /dev/null
+++ b/modules/Vtiger/helpers/ShowFile.php
@@ -0,0 +1,69 @@
+<?php
+/* +**********************************************************************************
+ * The contents of this file are subject to the Vtiger CRM Public License Version 1.1
+ * ("License"); You may not use this file except in compliance with the License
+ * The Original Code is: Vtiger CRM Commercial
+ * The Initial Developer of the Original Code is Vtiger.
+ * Portions created by Vtiger are Copyright (C) Vtiger.
+ * All Rights Reserved.
+ * ***********************************************************************************/
+
+class Vtiger_ShowFile_Helper {
+
+	/**
+	 * Function to display images out side of CRM (with out authentication)
+	 * @param type $fid - attachment id
+	 * @param type $encFileName - md5(filename)
+	 */
+	static function handle($fid, $encFileName) {
+        global $upload_badext;
+		$db = PearDatabase::getInstance();
+
+		$query = "SELECT vtiger_attachments.* FROM vtiger_attachments
+					INNER JOIN vtiger_crmentity ON vtiger_crmentity.crmid = vtiger_attachments.attachmentsid
+					WHERE vtiger_attachments.attachmentsid=? LIMIT 1";
+		$result = $db->pquery($query, array($fid));
+		if ($result && $db->num_rows($result)) {
+			$resultData	= $db->fetch_array($result);
+			$fileId		= $resultData['attachmentsid'];
+			$filePath	= $resultData['path'];
+			$fileName	= $resultData['name'];
+			$fileType	= $resultData['type'];
+			$sanitizedFileName = sanitizeUploadFileName($fileName, $upload_badext);
+
+			/**
+			 * While saving the document applying decode_html to save in DB, but this is not happening for the images
+			 * This save happens from mailroom, inbox, record save, document save etc..
+			 */
+			if (md5($fileName) == $encFileName || md5($sanitizedFileName) == $encFileName) {
+				$finalFilePath = $filePath.$fileId.'_'.Vtiger_Util_Helper::getEncryptedFileName($sanitizedFileName);
+				$isFileExist = false;
+				if (file_exists($finalFilePath)) {
+					$isFileExist = true;
+				} else {
+					$finalFilePath = $filePath.$fileId.'_'.$sanitizedFileName;
+					if (file_exists($finalFilePath)) {
+						$isFileExist = true;
+					}
+				}
+				if ($isFileExist) {
+					Vtiger_ShowFile_Helper::show($finalFilePath,$fileType);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Function to show images out side of CRM
+	 * @param type $finalFilePath - the proper image folder path
+	 * @param type $fileType - image file type
+	 */
+	static function show($finalFilePath, $fileType) {
+		$handle = fopen($finalFilePath, "rb");
+		$contents = fread($handle, filesize($finalFilePath));
+		fclose($handle);
+
+		header("Content-Type: $fileType;charset=UTF-8");
+		echo $contents;
+	}
+}
\ No newline at end of file
diff --git a/modules/Vtiger/helpers/Util.php b/modules/Vtiger/helpers/Util.php
index 1bb5ade98..4d793d451 100644
--- a/modules/Vtiger/helpers/Util.php
+++ b/modules/Vtiger/helpers/Util.php
@@ -1238,4 +1238,14 @@ class Vtiger_Util_Helper {
 			return preg_replace($pattern, '\\\\$0', $string);
 		}
 	}
+    
+    public static function getEncryptedFileName($sanitizedFileName) {
+		$encryptedFileName = $sanitizedFileName;
+		if ($sanitizedFileName) {
+			$fileNameParts = explode('.', decode_html($sanitizedFileName));
+			$fileType = array_pop($fileNameParts);
+			$encryptedFileName = md5(implode('.', $fileNameParts)).'.'.$fileType;
+		}
+		return $encryptedFileName;
+	}
 }
diff --git a/modules/Vtiger/models/Record.php b/modules/Vtiger/models/Record.php
index 2433bb897..b091aceef 100644
--- a/modules/Vtiger/models/Record.php
+++ b/modules/Vtiger/models/Record.php
@@ -397,6 +397,7 @@ class Vtiger_Record_Model extends Vtiger_Base_Model {
 	 * @return <array> Image Details List
 	 */
 	public function getImageDetails() {
+        global $site_URL;
 		$db = PearDatabase::getInstance();
 		$imageDetails = array();
 		$recordId = $this->getId();
@@ -412,7 +413,7 @@ class Vtiger_Record_Model extends Vtiger_Base_Model {
 			$imageId = $db->query_result($result, 0, 'attachmentsid');
 			$imagePath = $db->query_result($result, 0, 'path');
 			$imageName = $db->query_result($result, 0, 'name');
-
+            $url = \Vtiger_Functions::getFilePublicURL($imageId, $imageName);
 			//decode_html - added to handle UTF-8 characters in file names
 			$imageOriginalName = urlencode(decode_html($imageName));
 
@@ -421,7 +422,8 @@ class Vtiger_Record_Model extends Vtiger_Base_Model {
 						'id' => $imageId,
 						'orgname' => $imageOriginalName,
 						'path' => $imagePath.$imageId,
-						'name' => $imageName
+						'name' => $imageName,
+                        'url'  => $site_URL.$url
 				);
 			}
 		}
@@ -590,7 +592,7 @@ class Vtiger_Record_Model extends Vtiger_Base_Model {
 			$filePath = $fileDetails['path'];
 			$fileName = $fileDetails['name'];
 			$fileName = html_entity_decode($fileName, ENT_QUOTES, vglobal('default_charset'));
-			$savedFile = md5($fileDetails['attachmentsid']."_".$fileName);
+			$savedFile = $fileDetails['attachmentsid']."_".Vtiger_Util_Helper::getEncryptedFileName($fileName);
 			$fileSize = filesize($filePath.$savedFile);
 			$fileSize = $fileSize + ($fileSize % 1024);
 			if (fopen($filePath.$savedFile, "r")) {
diff --git a/pkg/vtiger/modules/ModComments/modules/ModComments/views/FilePreview.php b/pkg/vtiger/modules/ModComments/modules/ModComments/views/FilePreview.php
index 6816cbbb2..49be94669 100644
--- a/pkg/vtiger/modules/ModComments/modules/ModComments/views/FilePreview.php
+++ b/pkg/vtiger/modules/ModComments/modules/ModComments/views/FilePreview.php
@@ -37,7 +37,7 @@ class ModComments_FilePreview_View extends Vtiger_IndexAjax_View {
 			$filePath = $fileDetails['path'];
 			$fileName = $fileDetails['name'];
 			$fileName = html_entity_decode($fileName, ENT_QUOTES, vglobal('default_charset'));
-			$savedFile = md5($fileDetails['attachmentsid']."_".$fileName);
+			$savedFile = $fileDetails['attachmentsid']."_".Vtiger_Util_Helper::getEncryptedFileName($fileName);
 
 			$fileSize = filesize($filePath.$savedFile);
 			$fileSize = $fileSize + ($fileSize % 1024);
diff --git a/public.php b/public.php
new file mode 100644
index 000000000..337bb0cf9
--- /dev/null
+++ b/public.php
@@ -0,0 +1,15 @@
+<?php
+/*+***********************************************************************************
+ * The contents of this file are subject to the vtiger CRM Public License Version 1.0
+ * ("License"); You may not use this file except in compliance with the License
+ * The Original Code is:  vtiger CRM Open Source
+ * The Initial Developer of the Original Code is vtiger.
+ * Portions created by vtiger are Copyright (C) vtiger.
+ * All Rights Reserved.
+ *************************************************************************************/
+
+include_once 'vtlib/Vtiger/Module.php';
+include_once 'includes/Loader.php';
+vimport('includes.runtime.EntryPoint');
+
+Vtiger_ShowFile_Helper::handle(vtlib_purify($_REQUEST['fid']), vtlib_purify($_REQUEST['key']));
\ No newline at end of file
diff --git a/vtlib/Vtiger/Functions.php b/vtlib/Vtiger/Functions.php
index c3be52453..38bb8079b 100644
--- a/vtlib/Vtiger/Functions.php
+++ b/vtlib/Vtiger/Functions.php
@@ -1507,4 +1507,20 @@ class Vtiger_Functions {
         }
         return $ok;
     }
+    
+    /**
+	 * Function to get file public url to access outside of CRM (from emails)
+	 * @param <Integer> $fileId
+	 * @param <String> $fileName
+	 * @return <String> $sourceUrl
+	 */
+	public static function getFilePublicURL($imageId, $imageName) {
+		$publicUrl = '';
+        $fileId = $imageId;
+        $fileName = $imageName;
+		if ($fileId) {
+			$publicUrl = "public.php?fid=$fileId&key=".md5($fileName);
+		}
+		return $publicUrl;
+	}
 }
-- 
GitLab