mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-06 16:07:03 +03:00
Changes for BIMI-Selector #1394
This commit is contained in:
parent
8292c47f7c
commit
58955f792a
5 changed files with 28 additions and 10 deletions
|
|
@ -39,9 +39,15 @@
|
||||||
avatars = new Map,
|
avatars = new Map,
|
||||||
ncAvatars = new Map,
|
ncAvatars = new Map,
|
||||||
templateId = 'MailMessageView',
|
templateId = 'MailMessageView',
|
||||||
|
getBimiSelector = msg => {
|
||||||
|
// Get 's' value out of 'v=BIMI1; s=foo;'
|
||||||
|
let bimiSelector = msg.headers().valueByName('BIMI-Selector');
|
||||||
|
bimiSelector = bimiSelector ? bimiSelector.match(/;.*s=([^\s;]+)/)[1] : '';
|
||||||
|
return bimiSelector || '';
|
||||||
|
},
|
||||||
getAvatarUid = msg => {
|
getAvatarUid = msg => {
|
||||||
let from = msg.from[0],
|
let from = msg.from[0],
|
||||||
bimi = 'pass' == from.dkimStatus ? 1 : 0;
|
bimi = ('pass' == from.dkimStatus ? 1 : 0) + '-' + getBimiSelector(msg);
|
||||||
return `${bimi}/${from.email.toLowerCase()}`;
|
return `${bimi}/${from.email.toLowerCase()}`;
|
||||||
},
|
},
|
||||||
getAvatar = msg => ncAvatars.get(msg.from[0].email.toLowerCase()) || avatars.get(getAvatarUid(msg)),
|
getAvatar = msg => ncAvatars.get(msg.from[0].email.toLowerCase()) || avatars.get(getAvatarUid(msg)),
|
||||||
|
|
@ -97,6 +103,7 @@
|
||||||
runQueue();
|
runQueue();
|
||||||
}, 'Avatar', {
|
}, 'Avatar', {
|
||||||
bimi: 'pass' == from.dkimStatus ? 1 : 0,
|
bimi: 'pass' == from.dkimStatus ? 1 : 0,
|
||||||
|
bimiSelector: getBimiSelector(item[0]),
|
||||||
email: from.email
|
email: from.email
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,9 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
public function DoAvatar() : array
|
public function DoAvatar() : array
|
||||||
{
|
{
|
||||||
$bBimi = !empty($this->jsonParam('bimi'));
|
$bBimi = !empty($this->jsonParam('bimi'));
|
||||||
|
$sBimiSelector = $this->jsonParam('bimiSelector') ?: '';
|
||||||
$sEmail = $this->jsonParam('email');
|
$sEmail = $this->jsonParam('email');
|
||||||
$aResult = $this->getAvatar($sEmail, !empty($bBimi));
|
$aResult = $this->getAvatar($sEmail, $bBimi, $sBimiSelector);
|
||||||
if ($aResult) {
|
if ($aResult) {
|
||||||
$aResult = [
|
$aResult = [
|
||||||
'type' => $aResult[0],
|
'type' => $aResult[0],
|
||||||
|
|
@ -103,7 +104,9 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
public function ServiceAvatar(string $sServiceName, string $sBimi, string $sEmail)
|
public function ServiceAvatar(string $sServiceName, string $sBimi, string $sEmail)
|
||||||
{
|
{
|
||||||
$sEmail = \SnappyMail\Crypt::DecryptUrlSafe($sEmail);
|
$sEmail = \SnappyMail\Crypt::DecryptUrlSafe($sEmail);
|
||||||
if ($sEmail && ($aResult = $this->getAvatar($sEmail, !empty($sBimi)))) {
|
$aBimi = \explode('-', $sBimi, 2);
|
||||||
|
$sBimiSelector = isset($aBimi[1]) ? $aBimi[1] : 'default';
|
||||||
|
if ($sEmail && ($aResult = $this->getAvatar($sEmail, !empty($aBimi[0]), $sBimiSelector))) {
|
||||||
\header('Content-Type: '.$aResult[0]);
|
\header('Content-Type: '.$aResult[0]);
|
||||||
echo $aResult[1];
|
echo $aResult[1];
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -190,7 +193,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getAvatar(string $sEmail, bool $bBimi) : ?array
|
private function getAvatar(string $sEmail, bool $bBimi, string $sBimiSelector = '') : ?array
|
||||||
{
|
{
|
||||||
if (!\strpos($sEmail, '@')) {
|
if (!\strpos($sEmail, '@')) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -235,7 +238,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
$aUrls = [];
|
$aUrls = [];
|
||||||
|
|
||||||
if ($this->Config()->Get('plugin', 'bimi', false)) {
|
if ($this->Config()->Get('plugin', 'bimi', false)) {
|
||||||
$BIMI = $bBimi ? \SnappyMail\DNS::BIMI($sDomain) : null;
|
$BIMI = $bBimi ? \SnappyMail\DNS::BIMI($sDomain, $sBimiSelector) : null;
|
||||||
if ($BIMI) {
|
if ($BIMI) {
|
||||||
$aUrls[] = $BIMI;
|
$aUrls[] = $BIMI;
|
||||||
// $aResult = ['text/uri-list', $BIMI];
|
// $aResult = ['text/uri-list', $BIMI];
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,8 @@ class MailClient
|
||||||
MimeHeader::LIST_UNSUBSCRIBE,
|
MimeHeader::LIST_UNSUBSCRIBE,
|
||||||
// https://autocrypt.org/level1.html#the-autocrypt-header
|
// https://autocrypt.org/level1.html#the-autocrypt-header
|
||||||
MimeHeader::AUTOCRYPT,
|
MimeHeader::AUTOCRYPT,
|
||||||
|
// https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-04.html#bimi-selector
|
||||||
|
MimeHeader::BIMI_SELECTOR,
|
||||||
// SPAM
|
// SPAM
|
||||||
MimeHeader::X_SPAM_STATUS,
|
MimeHeader::X_SPAM_STATUS,
|
||||||
MimeHeader::X_SPAM_FLAG,
|
MimeHeader::X_SPAM_FLAG,
|
||||||
|
|
|
||||||
|
|
@ -93,5 +93,8 @@ abstract class Header
|
||||||
// https://autocrypt.org/level1.html#the-autocrypt-header
|
// https://autocrypt.org/level1.html#the-autocrypt-header
|
||||||
AUTOCRYPT = 'Autocrypt',
|
AUTOCRYPT = 'Autocrypt',
|
||||||
|
|
||||||
|
// https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-04.html#bimi-selector
|
||||||
|
BIMI_SELECTOR = 'BIMI-Selector',
|
||||||
|
|
||||||
LIST_UNSUBSCRIBE = 'List-Unsubscribe';
|
LIST_UNSUBSCRIBE = 'List-Unsubscribe';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,15 @@ abstract class DNS
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* $domain = 'bimigroup.org'
|
* $domain = 'bimigroup.org'
|
||||||
|
* $selector = 'default'
|
||||||
* Then a TXT lookup is done on 'default._bimi.bimigroup.org'
|
* Then a TXT lookup is done on 'default._bimi.bimigroup.org'
|
||||||
*/
|
*/
|
||||||
public static function BIMI(string $domain) : string
|
public static function BIMI(string $domain, string $selector = 'default') : string
|
||||||
{
|
{
|
||||||
|
$selector = \trim($selector) ?: 'default';
|
||||||
$oCache = \RainLoop\Api::Actions()->Cacher();
|
$oCache = \RainLoop\Api::Actions()->Cacher();
|
||||||
$BIMI = $oCache->Get("dns-bimi-{$domain}") ?: null;
|
$sCacheKey = "dns-bimi-{$domain}-{$selector}";
|
||||||
|
$BIMI = $oCache->Get($sCacheKey) ?: null;
|
||||||
if ($BIMI) {
|
if ($BIMI) {
|
||||||
$BIMI = \json_decode($BIMI);
|
$BIMI = \json_decode($BIMI);
|
||||||
if ($BIMI[1] < \time()) {
|
if ($BIMI[1] < \time()) {
|
||||||
|
|
@ -22,12 +25,12 @@ abstract class DNS
|
||||||
}
|
}
|
||||||
if (null === $BIMI) {
|
if (null === $BIMI) {
|
||||||
$BIMI = '';
|
$BIMI = '';
|
||||||
$values = \dns_get_record("default._bimi.{$domain}", \DNS_TXT);
|
$values = \dns_get_record("{$selector}._bimi.{$domain}", \DNS_TXT);
|
||||||
if ($values) {
|
if ($values) {
|
||||||
foreach ($values as $value) {
|
foreach ($values as $value) {
|
||||||
if (\str_starts_with($value['txt'], 'v=BIMI1')) {
|
if (\str_starts_with($value['txt'], 'v=BIMI1')) {
|
||||||
$BIMI = \preg_replace('/^.+l=([^;]+)(;.*)?$/D', '$1', $value['txt']);
|
$BIMI = \preg_replace('/^.+l=([^;]+)(;.*)?$/D', '$1', $value['txt']);
|
||||||
$oCache->Set("dns-bimi-{$domain}", \json_encode([
|
$oCache->Set($sCacheKey, \json_encode([
|
||||||
$BIMI,
|
$BIMI,
|
||||||
time() + $value['ttl']
|
time() + $value['ttl']
|
||||||
]));
|
]));
|
||||||
|
|
@ -37,7 +40,7 @@ abstract class DNS
|
||||||
}
|
}
|
||||||
if (!$BIMI) {
|
if (!$BIMI) {
|
||||||
// Don't lookup for 24 hours
|
// Don't lookup for 24 hours
|
||||||
$oCache->Set("dns-bimi-{$domain}", \json_encode([
|
$oCache->Set($sCacheKey, \json_encode([
|
||||||
$BIMI,
|
$BIMI,
|
||||||
time() + 86400
|
time() + 86400
|
||||||
]));
|
]));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue