diff --git a/dev/Mime/Utils.js b/dev/Mime/Utils.js index 8cf6c795e..7c038f675 100644 --- a/dev/Mime/Utils.js +++ b/dev/Mime/Utils.js @@ -35,9 +35,7 @@ export function MimeToMessage(data, message) attachment.url = part.dataUrl; attachment.estimatedSize = part.body.length; /* - attachment.isThumbnail = false; attachment.contentLocation = ''; - attachment.download = ''; attachment.folder = ''; attachment.uid = ''; attachment.mimeIndex = part.id; diff --git a/dev/Model/Attachment.js b/dev/Model/Attachment.js index 6b610981a..a69e4ba23 100644 --- a/dev/Model/Attachment.js +++ b/dev/Model/Attachment.js @@ -1,7 +1,8 @@ import ko from 'ko'; import { FileInfo, FileType } from 'Common/File'; -import { stopEvent } from 'Common/Globals'; +import { stopEvent, SettingsGet, SettingsCapa } from 'Common/Globals'; +import { b64EncodeJSONSafe } from 'Common/Utils'; import { attachmentDownload, serverRequestRaw @@ -23,10 +24,8 @@ export class AttachmentModel extends AbstractModel { this.fileName = ''; this.fileNameExt = ''; this.fileType = FileType.Unknown; - this.isThumbnail = false; this.cId = ''; this.contentLocation = ''; - this.download = ''; this.folder = ''; this.uid = ''; this.url = ''; @@ -126,6 +125,17 @@ export class AttachmentModel extends AbstractModel { ); } + get download() { + return b64EncodeJSONSafe({ + folder: this.folder, + uid: this.uid, + mimeIndex: this.mimeIndex, + mimeType: this.mimeType, + fileName: this.fileName, + accountHash: SettingsGet('accountHash') + }); + } + /** * @returns {string} */ @@ -144,7 +154,7 @@ export class AttachmentModel extends AbstractModel { * @returns {boolean} */ hasThumbnail() { - return this.isThumbnail && !this.isLinked(); + return SettingsCapa('AttachmentThumbnails') && this.isImage() && !this.isLinked(); } /** diff --git a/dev/Model/Message.js b/dev/Model/Message.js index cdedd8dad..06a6cd551 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -5,7 +5,7 @@ import { i18n } from 'Common/Translator'; import { doc, SettingsGet } from 'Common/Globals'; import { encodeHtml, plainToHtml, htmlToPlain, cleanHtml } from 'Common/Html'; -import { forEachObjectEntry } from 'Common/Utils'; +import { forEachObjectEntry, b64EncodeJSONSafe } from 'Common/Utils'; import { serverRequestRaw, proxy } from 'Common/Links'; import { addObservablesTo, addComputablesTo } from 'External/ko'; @@ -59,7 +59,6 @@ export class MessageModel extends AbstractModel { this.folder = ''; this.uid = 0; this.hash = ''; - this.requestHash = ''; this.from = new EmailCollectionModel; this.to = new EmailCollectionModel; this.cc = new EmailCollectionModel; @@ -178,6 +177,16 @@ export class MessageModel extends AbstractModel { }); } + get requestHash() { + return b64EncodeJSONSafe({ + folder: this.folder, + uid: this.uid, + mimeType: 'message/rfc822', + fileName: (this.subject() || 'message-' + this.hash) + '.eml', + accountHash: SettingsGet('accountHash') + }); + } + toggleTag(keyword) { toggleTag(this, keyword); } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Utils.php b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Utils.php index 1d9404562..7f439d1a0 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Utils.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Utils.php @@ -18,24 +18,6 @@ namespace MailSo\Base; abstract class Utils { - public static function fileHasThumbnail(string $sFileName) : bool - { - static $aCache = array(); - - $sExt = static::GetFileExtension($sFileName); - if (isset($aCache[$sExt])) { - return $aCache[$sExt]; - } - - $aCache[$sExt] = ( - \extension_loaded('gd') - || \extension_loaded('gmagick') - || \extension_loaded('imagick') - ) && \in_array($sExt, ['png', 'gif', 'jpg', 'jpeg', 'webp']); - - return $aCache[$sExt]; - } - public static function NormalizeCharset(string $sEncoding, bool $bAsciAsUtf8 = false) : string { $sEncoding = \preg_replace('/^iso8/', 'iso-8', \strtolower($sEncoding)); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Attachment.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Attachment.php index f79679a51..aa11a1c81 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Attachment.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Attachment.php @@ -59,20 +59,10 @@ class Attachment implements \JsonSerializable #[\ReturnTypeWillChange] public function jsonSerialize() { - $aResult = \array_merge([ + return \array_merge([ '@Object' => 'Object/Attachment', 'folder' => $this->sFolder, 'uid' => $this->iUid ], $this->oBodyStructure->jsonSerialize()); - $aResult['isThumbnail'] = \MailSo\Base\Utils::fileHasThumbnail($aResult['fileName']); - $oActions = \RainLoop\Api::Actions(); - $aResult['download'] = $oActions->encodeRawKey(array( - 'folder' => $aResult['folder'], - 'uid' => $aResult['uid'], - 'mimeIndex' => $aResult['mimeIndex'], - 'mimeType' => $aResult['mimeType'], - 'fileName' => $aResult['fileName'] - )); - return $aResult; } } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php index 128d656d3..494970373 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -1080,13 +1080,19 @@ class Actions public function encodeRawKey(array $aValues): string { - return \SnappyMail\Crypt::EncryptUrlSafe($aValues, \sha1(APP_SALT . $this->getAccountFromToken()->Hash())); + $aValues['accountHash'] = $this->getAccountFromToken()->Hash(); + return \MailSo\Base\Utils::UrlSafeBase64Encode(\json_encode($aValues)); } protected function decodeRawKey(string $sRawKey): array { return empty($sRawKey) ? [] - : (\SnappyMail\Crypt::DecryptUrlSafe($sRawKey, \sha1(APP_SALT . $this->getAccountFromToken()->Hash())) ?: []); + : (\json_decode(\MailSo\Base\Utils::UrlSafeBase64Decode($sRawKey), true) ?: []); +/* + if (empty($aValues['accountHash']) || $aValues['accountHash'] !== $oAccount->Hash()) { + return []; + } +*/ } public function StaticCache(): string diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Raw.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Raw.php index 9ded52901..58fda8ab7 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Raw.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Raw.php @@ -9,21 +9,28 @@ trait Raw */ public function RawViewAsPlain() : bool { - $oAccount = $this->initMailClientConnection(); - - $aValues = $this->decodeRawKey((string) $this->GetActionParam('RawKey', '')); - - $sFolder = isset($aValues['folder']) ? (string) $aValues['folder'] : ''; - $iUid = isset($aValues['uid']) ? (int) $aValues['uid'] : 0; - $sMimeIndex = isset($aValues['mimeIndex']) ? (string) $aValues['mimeIndex'] : ''; - - \header('Content-Type: text/plain'); - - return $this->MailClient()->MessageMimeStream(function ($rResource) { - if (\is_resource($rResource)) { - \MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource); - } - }, $sFolder, $iUid, $sMimeIndex); + $oAccount = $this->getAccountFromToken(); + $sRawKey = $this->GetActionParam('RawKey', ''); + $aValues = $this->decodeRawKey($sRawKey); + if (!empty($aValues['folder']) && !empty($aValues['uid']) + && !empty($aValues['accountHash']) && $aValues['accountHash'] === $oAccount->Hash() + ) { + $this->verifyCacheByKey($sRawKey); + $this->initMailClientConnection(); + \header('Content-Type: text/plain'); + return $this->MailClient()->MessageMimeStream( + function ($rResource) use ($sRawKey) { + if (\is_resource($rResource)) { + $this->cacheByKey($sRawKey); + \MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource); + } + }, + (string) $aValues['folder'], + (int) $aValues['uid'], + isset($aValues['mimeIndex']) ? (string) $aValues['mimeIndex'] : '' + ); + } + return false; } public function RawDownload() : bool @@ -69,71 +76,36 @@ trait Raw return false; } - public function RawPublic() : bool - { - $sRawKey = (string) $this->GetActionParam('RawKey', ''); - $this->verifyCacheByKey($sRawKey); - - $sHash = $sRawKey; - $sData = ''; - - if (!empty($sHash)) { - $sData = $this->StorageProvider()->Get(null, - \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, - \RainLoop\KeyPathHelper::PublicFile($sHash) - ); - } - - $aMatch = array(); - if (!empty($sData) && 0 === \strpos($sData, 'data:') && - \preg_match('/^data:([^:]+):/', $sData, $aMatch) && !empty($aMatch[1])) - { - $sContentType = \trim($aMatch[1]); - if (\in_array($sContentType, array('image/png', 'image/jpg', 'image/jpeg'))) { - $this->cacheByKey($sRawKey); - - \header('Content-Type: '.$sContentType); - echo \preg_replace('/^data:[^:]+:/', '', $sData); - unset($sData); - - return true; - } - } - - return false; - } - + /** + * Message, Message Attachment or Zip + */ private function rawSmart(bool $bDownload, bool $bThumbnail = false) : bool { $sRawKey = (string) $this->GetActionParam('RawKey', ''); $oAccount = $this->getAccountFromToken(); $aValues = $this->decodeRawKey($sRawKey); + if (empty($aValues['accountHash']) || $aValues['accountHash'] !== $oAccount->Hash()) { + return false; + } $sRange = \MailSo\Base\Http::GetHeader('Range'); - $aMatch = array(); $sRangeStart = $sRangeEnd = ''; $bIsRangeRequest = false; - if (!empty($sRange) && 'bytes=0-' !== \strtolower($sRange) && \preg_match('/^bytes=([0-9]+)-([0-9]*)/i', \trim($sRange), $aMatch)) { $sRangeStart = $aMatch[1]; $sRangeEnd = $aMatch[2]; - $bIsRangeRequest = true; } - $sFolder = isset($aValues['folder']) ? (string) $aValues['folder'] : ''; - $iUid = isset($aValues['uid']) ? (int) $aValues['uid'] : 0; $sMimeIndex = isset($aValues['mimeIndex']) ? (string) $aValues['mimeIndex'] : ''; - $sContentTypeIn = isset($aValues['mimeType']) ? (string) $aValues['mimeType'] : ''; $sFileNameIn = isset($aValues['fileName']) ? (string) $aValues['fileName'] : ''; - $sFileHashIn = isset($aValues['fileHash']) ? (string) $aValues['fileHash'] : ''; - if (!empty($sFileHashIn)) { + if (!empty($aValues['fileHash'])) { $this->verifyCacheByKey($sRawKey); // https://github.com/the-djmaze/snappymail/issues/144 @@ -147,7 +119,7 @@ trait Raw $sFileNameOut = $this->MainClearFileName($sFileNameIn, $sContentTypeIn, $sMimeIndex); - $rResource = $this->FilesProvider()->GetFile($oAccount, $sFileHashIn); + $rResource = $this->FilesProvider()->GetFile($oAccount, (string) $aValues['fileHash']); if (\is_resource($rResource)) { \header('Content-Type: '.$sContentTypeOut); \header('Content-Disposition: attachment; '. @@ -162,11 +134,15 @@ trait Raw return false; } - else if (!empty($sFolder) && 0 < $iUid) - { - $this->verifyCacheByKey($sRawKey); + + $sFolder = isset($aValues['folder']) ? (string) $aValues['folder'] : ''; + $iUid = isset($aValues['uid']) ? (int) $aValues['uid'] : 0; + if (empty($sFolder) || 1 > $iUid) { + return false; } + $this->verifyCacheByKey($sRawKey); + $this->initMailClientConnection(); $self = $this; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php index 7e8a3752e..4522e235e 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php @@ -94,8 +94,6 @@ trait Response if ($mResponse instanceof \MailSo\Mail\Message) { $aResult = $mResponse->jsonSerialize(); - $oAccount = $this->getAccountFromToken(); - if (!$aResult['dateTimeStampInUTC'] || $this->Config()->Get('labs', 'date_from_headers', true)) { $iDateTimeStampInUTC = $mResponse->HeaderTimeStampInUTC; if ($iDateTimeStampInUTC) { @@ -103,20 +101,9 @@ trait Response } } - // \MailSo\Mime\EmailCollection - foreach (['replyTo','from','to','cc','bcc','sender','deliveredTo'] as $prop) { - $aResult[$prop] = $this->responseObject($aResult[$prop], $prop); - } - - $sSubject = $aResult['subject']; - $aResult['requestHash'] = $this->encodeRawKey(array( - 'folder' => $aResult['folder'], - 'uid' => $aResult['uid'], - 'mimeType' => 'message/rfc822', - 'fileName' => (\strlen($sSubject) ? \MailSo\Base\Utils::SecureFileName($sSubject) : 'message-'.$aResult['uid']) . '.eml' - )); - if (!$sParent) { + $oAccount = $this->getAccountFromToken(); + $aResult['draftInfo'] = $mResponse->DraftInfo; $aResult['unsubsribeLinks'] = $mResponse->UnsubsribeLinks; $aResult['references'] = $mResponse->References;