From 58955f792a8a0681c4b317b2ea3b8b12fa6ed7f4 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 22 Jan 2024 00:01:46 +0100 Subject: [PATCH] Changes for BIMI-Selector #1394 --- plugins/avatars/avatars.js | 9 ++++++++- plugins/avatars/index.php | 11 +++++++---- .../0.0.0/app/libraries/MailSo/Mail/MailClient.php | 2 ++ .../libraries/MailSo/Mime/Enumerations/Header.php | 3 +++ snappymail/v/0.0.0/app/libraries/snappymail/dns.php | 13 ++++++++----- 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/plugins/avatars/avatars.js b/plugins/avatars/avatars.js index 4fd61a924..d9f07de74 100644 --- a/plugins/avatars/avatars.js +++ b/plugins/avatars/avatars.js @@ -39,9 +39,15 @@ avatars = new Map, ncAvatars = new Map, 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 => { let from = msg.from[0], - bimi = 'pass' == from.dkimStatus ? 1 : 0; + bimi = ('pass' == from.dkimStatus ? 1 : 0) + '-' + getBimiSelector(msg); return `${bimi}/${from.email.toLowerCase()}`; }, getAvatar = msg => ncAvatars.get(msg.from[0].email.toLowerCase()) || avatars.get(getAvatarUid(msg)), @@ -97,6 +103,7 @@ runQueue(); }, 'Avatar', { bimi: 'pass' == from.dkimStatus ? 1 : 0, + bimiSelector: getBimiSelector(item[0]), email: from.email }); break; diff --git a/plugins/avatars/index.php b/plugins/avatars/index.php index 41c19ee8c..5e9854a16 100644 --- a/plugins/avatars/index.php +++ b/plugins/avatars/index.php @@ -84,8 +84,9 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin public function DoAvatar() : array { $bBimi = !empty($this->jsonParam('bimi')); + $sBimiSelector = $this->jsonParam('bimiSelector') ?: ''; $sEmail = $this->jsonParam('email'); - $aResult = $this->getAvatar($sEmail, !empty($bBimi)); + $aResult = $this->getAvatar($sEmail, $bBimi, $sBimiSelector); if ($aResult) { $aResult = [ 'type' => $aResult[0], @@ -103,7 +104,9 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin public function ServiceAvatar(string $sServiceName, string $sBimi, string $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]); echo $aResult[1]; } else { @@ -190,7 +193,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin return null; } - private function getAvatar(string $sEmail, bool $bBimi) : ?array + private function getAvatar(string $sEmail, bool $bBimi, string $sBimiSelector = '') : ?array { if (!\strpos($sEmail, '@')) { return null; @@ -235,7 +238,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin $aUrls = []; if ($this->Config()->Get('plugin', 'bimi', false)) { - $BIMI = $bBimi ? \SnappyMail\DNS::BIMI($sDomain) : null; + $BIMI = $bBimi ? \SnappyMail\DNS::BIMI($sDomain, $sBimiSelector) : null; if ($BIMI) { $aUrls[] = $BIMI; // $aResult = ['text/uri-list', $BIMI]; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php index a81a50a3a..994ed4feb 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php @@ -75,6 +75,8 @@ class MailClient MimeHeader::LIST_UNSUBSCRIBE, // https://autocrypt.org/level1.html#the-autocrypt-header MimeHeader::AUTOCRYPT, + // https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-04.html#bimi-selector + MimeHeader::BIMI_SELECTOR, // SPAM MimeHeader::X_SPAM_STATUS, MimeHeader::X_SPAM_FLAG, diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Enumerations/Header.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Enumerations/Header.php index 53c74daeb..a65a25ff4 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Enumerations/Header.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Enumerations/Header.php @@ -93,5 +93,8 @@ abstract class Header // https://autocrypt.org/level1.html#the-autocrypt-header 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'; } diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/dns.php b/snappymail/v/0.0.0/app/libraries/snappymail/dns.php index cb3ebda20..c48f4f1c0 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/dns.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/dns.php @@ -6,12 +6,15 @@ abstract class DNS { /** * $domain = 'bimigroup.org' + * $selector = 'default' * 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(); - $BIMI = $oCache->Get("dns-bimi-{$domain}") ?: null; + $sCacheKey = "dns-bimi-{$domain}-{$selector}"; + $BIMI = $oCache->Get($sCacheKey) ?: null; if ($BIMI) { $BIMI = \json_decode($BIMI); if ($BIMI[1] < \time()) { @@ -22,12 +25,12 @@ abstract class DNS } if (null === $BIMI) { $BIMI = ''; - $values = \dns_get_record("default._bimi.{$domain}", \DNS_TXT); + $values = \dns_get_record("{$selector}._bimi.{$domain}", \DNS_TXT); if ($values) { foreach ($values as $value) { if (\str_starts_with($value['txt'], 'v=BIMI1')) { $BIMI = \preg_replace('/^.+l=([^;]+)(;.*)?$/D', '$1', $value['txt']); - $oCache->Set("dns-bimi-{$domain}", \json_encode([ + $oCache->Set($sCacheKey, \json_encode([ $BIMI, time() + $value['ttl'] ])); @@ -37,7 +40,7 @@ abstract class DNS } if (!$BIMI) { // Don't lookup for 24 hours - $oCache->Set("dns-bimi-{$domain}", \json_encode([ + $oCache->Set($sCacheKey, \json_encode([ $BIMI, time() + 86400 ]));