Redesign Raw handling as encodeRawKey/decodeRawKey doesn't need encryption

This commit is contained in:
the-djmaze 2023-03-07 13:53:52 +01:00
parent 402de0d569
commit bd7f9856f2
8 changed files with 73 additions and 115 deletions

View file

@ -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;

View file

@ -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();
}
/**

View file

@ -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);
}

View file

@ -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));

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;

View file

@ -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;