mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Changes for #714
This commit is contained in:
parent
a085bbb51d
commit
e5ed52b79e
5 changed files with 55 additions and 39 deletions
|
|
@ -105,6 +105,7 @@ export class AbstractModel {
|
||||||
// fall through
|
// fall through
|
||||||
case 'undefined':
|
case 'undefined':
|
||||||
default:
|
default:
|
||||||
|
this[key] = value;
|
||||||
// console.log((typeof this[key])+' '+(model.name)+'.'+key+' not revived');
|
// console.log((typeof this[key])+' '+(model.name)+'.'+key+' not revived');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
(rl => {
|
(rl => {
|
||||||
// if (rl.settings.get('Nextcloud'))
|
|
||||||
const
|
const
|
||||||
queue = [],
|
queue = [],
|
||||||
avatars = new Map,
|
avatars = new Map,
|
||||||
|
|
@ -45,6 +44,9 @@
|
||||||
fn = url=>{element.src = url};
|
fn = url=>{element.src = url};
|
||||||
if (url) {
|
if (url) {
|
||||||
fn(url);
|
fn(url);
|
||||||
|
} else if (msg.avatar) {
|
||||||
|
let bimi = 'pass' == msg.from[0].dkimStatus ? 1 : 0;
|
||||||
|
fn(`?Avatar/${bimi}/${msg.avatar}`);
|
||||||
} else {
|
} else {
|
||||||
queue.push([msg, fn]);
|
queue.push([msg, fn]);
|
||||||
runQueue();
|
runQueue();
|
||||||
|
|
@ -80,6 +82,9 @@
|
||||||
};
|
};
|
||||||
if (url) {
|
if (url) {
|
||||||
fn(url);
|
fn(url);
|
||||||
|
} else if (msg.avatar) {
|
||||||
|
let bimi = 'pass' == msg.from[0].dkimStatus ? 1 : 0;
|
||||||
|
fn(`?Avatar/${bimi}/${msg.avatar}`);
|
||||||
} else {
|
} else {
|
||||||
// let from = msg.from[0], bimi = 'pass' == from.dkimStatus ? 1 : 0;
|
// let from = msg.from[0], bimi = 'pass' == from.dkimStatus ? 1 : 0;
|
||||||
// view.viewUserPic(`?Avatar/${bimi}/${encodeURIComponent(from.email)}`);
|
// view.viewUserPic(`?Avatar/${bimi}/${encodeURIComponent(from.email)}`);
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
{
|
{
|
||||||
const
|
const
|
||||||
NAME = 'Avatar',
|
NAME = 'Avatars',
|
||||||
AUTHOR = 'SnappyMail',
|
AUTHOR = 'SnappyMail',
|
||||||
URL = 'https://snappymail.eu/',
|
URL = 'https://snappymail.eu/',
|
||||||
VERSION = '1.0',
|
VERSION = '1.1',
|
||||||
RELEASE = '2022-11-23',
|
RELEASE = '2022-11-23',
|
||||||
REQUIRED = '2.22.0',
|
REQUIRED = '2.22.0',
|
||||||
CATEGORY = 'Contacts',
|
CATEGORY = 'Contacts',
|
||||||
|
|
@ -19,6 +19,29 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$this->addJs('avatars.js');
|
$this->addJs('avatars.js');
|
||||||
$this->addJsonHook('Avatar', 'DoAvatar');
|
$this->addJsonHook('Avatar', 'DoAvatar');
|
||||||
$this->addPartHook('Avatar', 'ServiceAvatar');
|
$this->addPartHook('Avatar', 'ServiceAvatar');
|
||||||
|
// TODO: https://github.com/the-djmaze/snappymail/issues/714
|
||||||
|
// $this->addHook('filter.json-response', 'FilterJsonResponse');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function FilterJsonResponse(string $sAction, array &$aResponseItem)
|
||||||
|
{
|
||||||
|
if ('MessageList' === $sAction && !empty($aResponseItem['Result']['@Collection'])) {
|
||||||
|
foreach ($aResponseItem['Result']['@Collection'] as $id => $message) {
|
||||||
|
$aResponseItem['Result']['@Collection'][$id]['Avatar'] = static::encryptFrom($message['From'][0]);
|
||||||
|
}
|
||||||
|
} else if ('Message' === $sAction && !empty($aResponseItem['Result']['From'])) {
|
||||||
|
$aResponseItem['Result']['Avatar'] = static::encryptFrom($aResponseItem['Result']['From'][0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function encryptFrom($mFrom)
|
||||||
|
{
|
||||||
|
if ($mFrom instanceof \MailSo\Mime\Email) {
|
||||||
|
$mFrom = $mFrom->jsonSerialize();
|
||||||
|
}
|
||||||
|
return \is_array($mFrom)
|
||||||
|
? \SnappyMail\Crypt::EncryptUrlSafe($mFrom['Email'])
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -28,7 +51,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
{
|
{
|
||||||
$bBimi = !empty($this->jsonParam('bimi'));
|
$bBimi = !empty($this->jsonParam('bimi'));
|
||||||
$sEmail = $this->jsonParam('email');
|
$sEmail = $this->jsonParam('email');
|
||||||
$aResult = $this->getAvatar(\urldecode($sEmail), !empty($sEmail));
|
$aResult = $this->getAvatar($sEmail, !empty($bBimi));
|
||||||
if ($aResult) {
|
if ($aResult) {
|
||||||
$aResult = [
|
$aResult = [
|
||||||
'type' => $aResult[0],
|
'type' => $aResult[0],
|
||||||
|
|
@ -39,15 +62,17 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /?Avatar/${bimi}/${from.email}
|
* GET /?Avatar/${bimi}/Encrypted(${from.email})
|
||||||
* Not fond of this idea because email address is exposed
|
* Nextcloud Mail uses insecure unencrypted 'index.php/apps/mail/api/avatars/url/local%40example.com'
|
||||||
* Maybe use btoa(from.email) or Crypto.subtle.encrypt({name:'AES-GCM',iv:''}, token, from.email)
|
|
||||||
*/
|
*/
|
||||||
// public function ServiceAvatar(...$aParts)
|
// public function ServiceAvatar(...$aParts)
|
||||||
public function ServiceAvatar(string $sServiceName, string $sBimi, string $sEmail)
|
public function ServiceAvatar(string $sServiceName, string $sBimi, string $sEmail)
|
||||||
{
|
{
|
||||||
$aResult = $this->getAvatar(\urldecode($sEmail), !empty($sEmail));
|
$sEmail = \SnappyMail\Crypt::DecryptUrlSafe($sEmail);
|
||||||
if ($aResult) {
|
$oActions = \RainLoop\Api::Actions();
|
||||||
|
$oActions->verifyCacheByKey($sEmail, true);
|
||||||
|
if ($sEmail && ($aResult = $this->getAvatar($sEmail, !empty($sBimi)))) {
|
||||||
|
$oActions->Http()->ServerUseCache($oActions->etag($sEmail), \time(), \time() + 86400);
|
||||||
\header('Content-Type: '.$aResult[0]);
|
\header('Content-Type: '.$aResult[0]);
|
||||||
echo $aResult[1];
|
echo $aResult[1];
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -74,7 +99,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
$oActions = \RainLoop\Api::Actions();
|
$oActions = \RainLoop\Api::Actions();
|
||||||
$oActions->verifyCacheByKey($sEmail);
|
// $oActions->verifyCacheByKey($sEmail, true);
|
||||||
|
|
||||||
$aResult = null;
|
$aResult = null;
|
||||||
|
|
||||||
|
|
@ -88,7 +113,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
\mime_content_type($aFiles[0]),
|
\mime_content_type($aFiles[0]),
|
||||||
\file_get_contents($aFiles[0])
|
\file_get_contents($aFiles[0])
|
||||||
];
|
];
|
||||||
$oActions->cacheByKey($sEmail);
|
// $oActions->Http()->ServerUseCache($oActions->etag($sEmail), \time(), \time() + 86400);
|
||||||
return $aResult;
|
return $aResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +192,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$oActions->cacheByKey($sEmail);
|
// $oActions->Http()->ServerUseCache($oActions->etag($sEmail), \time(), \time() + 86400);
|
||||||
|
|
||||||
return $aResult;
|
return $aResult;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,30 +18,20 @@ namespace MailSo\Cache\Drivers;
|
||||||
*/
|
*/
|
||||||
class File implements \MailSo\Cache\DriverInterface
|
class File implements \MailSo\Cache\DriverInterface
|
||||||
{
|
{
|
||||||
/**
|
private string $sCacheFolder;
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sCacheFolder;
|
|
||||||
|
|
||||||
/**
|
private string $sKeyPrefix = '';
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $sKeyPrefix;
|
|
||||||
|
|
||||||
function __construct(string $sCacheFolder, string $sKeyPrefix = '')
|
function __construct(string $sCacheFolder, string $sKeyPrefix = '')
|
||||||
{
|
{
|
||||||
$this->sCacheFolder = $sCacheFolder;
|
$this->sCacheFolder = \rtrim(\trim($sCacheFolder), '\\/').'/';
|
||||||
$this->sCacheFolder = rtrim(trim($this->sCacheFolder), '\\/').'/';
|
if (!empty($sKeyPrefix)) {
|
||||||
|
$sKeyPrefix = \str_pad(\preg_replace('/[^a-zA-Z0-9_]/', '_',
|
||||||
$this->sKeyPrefix = $sKeyPrefix;
|
\rtrim(\trim($sKeyPrefix), '\\/')), 5, '_');
|
||||||
if (!empty($this->sKeyPrefix))
|
|
||||||
{
|
|
||||||
$this->sKeyPrefix = \str_pad(\preg_replace('/[^a-zA-Z0-9_]/', '_',
|
|
||||||
rtrim(trim($this->sKeyPrefix), '\\/')), 5, '_');
|
|
||||||
|
|
||||||
$this->sKeyPrefix = '__/'.
|
$this->sKeyPrefix = '__/'.
|
||||||
\substr($this->sKeyPrefix, 0, 2).'/'.\substr($this->sKeyPrefix, 2, 2).'/'.
|
\substr($sKeyPrefix, 0, 2).'/'.\substr($sKeyPrefix, 2, 2).'/'.
|
||||||
$this->sKeyPrefix.'/';
|
$sKeyPrefix.'/';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1067,25 +1067,20 @@ class Actions
|
||||||
|
|
||||||
public function cacheByKey(string $sKey, bool $bForce = false): bool
|
public function cacheByKey(string $sKey, bool $bForce = false): bool
|
||||||
{
|
{
|
||||||
$bResult = false;
|
|
||||||
if (!empty($sKey) && ($bForce || ($this->oConfig->Get('cache', 'enable', true) && $this->oConfig->Get('cache', 'http', true)))) {
|
if (!empty($sKey) && ($bForce || ($this->oConfig->Get('cache', 'enable', true) && $this->oConfig->Get('cache', 'http', true)))) {
|
||||||
$iExpires = $this->oConfig->Get('cache', 'http_expires', 3600);
|
$iExpires = $this->oConfig->Get('cache', 'http_expires', 3600);
|
||||||
if (0 < $iExpires) {
|
if (0 < $iExpires) {
|
||||||
$this->Http()->ServerUseCache($this->etag($sKey), 1382478804, \time() + $iExpires);
|
$this->Http()->ServerUseCache($this->etag($sKey), 1382478804, \time() + $iExpires);
|
||||||
$bResult = true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->Http()->ServerNoCache();
|
||||||
if (!$bResult) {
|
return false;
|
||||||
$this->Http()->ServerNoCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $bResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function verifyCacheByKey(string $sKey, bool $bForce = false): void
|
public function verifyCacheByKey(string $sKey, bool $bForce = false): void
|
||||||
{
|
{
|
||||||
if (!empty($sKey) && ($bForce || $this->oConfig->Get('cache', 'enable', true) && $this->oConfig->Get('cache', 'http', true))) {
|
if (!empty($sKey) && ($bForce || ($this->oConfig->Get('cache', 'enable', true) && $this->oConfig->Get('cache', 'http', true)))) {
|
||||||
$sIfNoneMatch = $this->Http()->GetHeader('If-None-Match', '');
|
$sIfNoneMatch = $this->Http()->GetHeader('If-None-Match', '');
|
||||||
if ($this->etag($sKey) === $sIfNoneMatch) {
|
if ($this->etag($sKey) === $sIfNoneMatch) {
|
||||||
\MailSo\Base\Http::StatusHeader(304);
|
\MailSo\Base\Http::StatusHeader(304);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue