Improceved IDN emailaddress handling

This commit is contained in:
the-djmaze 2026-11-02 03:13:39 +01:00
parent 5d43aeef0b
commit 913d7a8b32
9 changed files with 42 additions and 24 deletions

View file

@ -48,7 +48,7 @@ class Email implements \JsonSerializable
/**
* @throws \ValueError
*/
public static function Parse(string $sEmailAddress) : self
public static function Parse(string $sEmailAddress): self
{
$sEmailAddress = Utils::Trim(Utils::DecodeHeaderValue($sEmailAddress));
if (!\strlen(\trim($sEmailAddress))) {
@ -153,32 +153,37 @@ class Email implements \JsonSerializable
return new self($sEmail, $sName);
}
public function GetEmail(bool $bUtf8 = false) : string
public function GetEmail(bool $bUtf8 = false): string
{
return $bUtf8 ? \SnappyMail\IDN::emailToUtf8($this->sEmail) : $this->sEmail;
}
public function GetDisplayName() : string
public function GetEmailUtf8(): string
{
return \SnappyMail\IDN::emailToUtf8($this->sEmail);
}
public function GetDisplayName(): string
{
return $this->sDisplayName;
}
public function getLocalPart() : string
public function getLocalPart(): string
{
return Utils::getEmailAddressLocalPart($this->sEmail);
}
public function GetDomain(bool $bIdn = false) : string
public function GetDomain(bool $bIdn = false): string
{
return Utils::getEmailAddressDomain($this->GetEmail($bIdn));
}
public function SetDkimStatus(string $sDkimStatus)
public function SetDkimStatus(string $sDkimStatus): void
{
$this->sDkimStatus = Enumerations\DkimStatus::normalizeValue($sDkimStatus);
}
public function ToString(bool $bConvertSpecialsName = false, bool $bUtf8 = false) : string
public function ToString(bool $bConvertSpecialsName = false, bool $bUtf8 = false): string
{
$sReturn = '';
if (\strlen($this->sEmail)) {
@ -195,7 +200,7 @@ class Email implements \JsonSerializable
return $sReturn;
}
public function __toString() : string
public function __toString(): string
{
return $this->ToString();
}
@ -206,7 +211,7 @@ class Email implements \JsonSerializable
return array(
'@Object' => 'Object/Email',
'name' => Utils::Utf8Clear($this->sDisplayName),
'email' => Utils::Utf8Clear($this->GetEmail(true)),
'email' => Utils::Utf8Clear($this->GetEmailUtf8()),
'dkimStatus' => $this->sDkimStatus
);
}

View file

@ -81,7 +81,7 @@ trait Accounts
$oMainAccount = $this->getMainAccountFromToken();
$aAccounts = $this->GetAccounts($oMainAccount);
$sEmail = \trim($this->GetActionParam('email', ''));
$sEmail = IDN::emailToAscii(\trim($this->GetActionParam('email', '')));
$oPassword = new \SnappyMail\SensitiveString($this->GetActionParam('password', ''));
$bNew = !empty($this->GetActionParam('new', 1));
@ -176,8 +176,7 @@ trait Accounts
return $this->FalseResponse();
}
$sEmailToDelete = \trim($this->GetActionParam('emailToDelete', ''));
$sEmailToDelete = IDN::emailToAscii($sEmailToDelete);
$sEmailToDelete = IDN::emailToAscii(\trim($this->GetActionParam('emailToDelete', '')));
$aAccounts = $this->GetAccounts($oMainAccount);
@ -252,7 +251,7 @@ trait Accounts
*/
public function DoAccountSwitch(): array
{
if ($this->switchAccount(\trim($this->GetActionParam('Email', '')))) {
if ($this->switchAccount(new \MailSo\Mime\Email($this->GetActionParam('Email', '')))) {
$oAccount = $this->getAccountFromToken();
$aResult = $this->getAccountData($oAccount);
// $this->Plugins()->InitAppData($bAdmin, $aResult, $oAccount);

View file

@ -64,7 +64,7 @@ trait AdminDomains
public function DoAdminDomainMatch() : array
{
$sCredentials = $this->resolveLoginCredentials(
$this->GetActionParam('username'),
new \MailSo\Mime\Email($this->GetActionParam('username')),
new \SnappyMail\SensitiveString('********')
);
$sEmail = $sCredentials['email'];

View file

@ -335,7 +335,7 @@ trait Messages
$oToCollection = $oMessage->GetTo();
if ($oToCollection) {
foreach ($oToCollection as /* @var $oEmail \MailSo\Mime\Email */ $oEmail) {
$aArrayToFrec[$oEmail->GetEmail(true)] = $oEmail->ToString(false, true);
$aArrayToFrec[$oEmail->GetEmailUtf8()] = $oEmail->ToString(false, true);
}
}

View file

@ -198,6 +198,7 @@ trait Pgp
$sKey = $this->GetActionParam('key', '');
$sKeyId = $this->GetActionParam('keyId', '');
$sEmail = $this->GetActionParam('email', '');
// $sEmail = \SnappyMail\IDN::emailToAscii($this->GetActionParam('email', ''));
if (!$sKey) {
try {

View file

@ -62,6 +62,7 @@ trait SMime
$cert = new Certificate();
$cert->distinguishedName['commonName'] = $this->GetActionParam('name', '') ?: $oAccount->Name();
$cert->distinguishedName['emailAddress'] = $this->GetActionParam('email', '') ?: $oAccount->Email();
// $cert->distinguishedName['emailAddress'] = \SnappyMail\IDN::emailToAscii($this->GetActionParam('email', '') ?: $oAccount->Email());
$result = $cert->createSelfSigned($oPassphrase, $this->GetActionParam('privateKey', ''));
return $this->DefaultResponse($result ?: false);
}

View file

@ -2,6 +2,7 @@
namespace RainLoop\Actions;
use MailSo\Mime\Email;
use RainLoop\Enumerations\Capa;
use RainLoop\Notifications;
use RainLoop\Utils;
@ -33,9 +34,9 @@ trait UserAuth
/**
* @throws \RainLoop\Exceptions\ClientException
*/
protected function resolveLoginCredentials(string $sEmail, SensitiveString $oPassword): array
protected function resolveLoginCredentials(Email $oEmail, SensitiveString $oPassword): array
{
$sEmail = \SnappyMail\IDN::emailToAscii(\MailSo\Base\Utils::Trim($sEmail));
$sEmail = $oEmail->GetEmail();
$sNewEmail = $sEmail;
$this->Plugins()->RunHook('login.credentials.step-1', array(&$sNewEmail));
@ -139,9 +140,10 @@ trait UserAuth
/**
* @throws \RainLoop\Exceptions\ClientException
*/
// public function LoginProcess(Email $sEmail, SensitiveString $oPassword, bool $bMainAccount = true): Account
public function LoginProcess(string $sEmail, SensitiveString $oPassword, bool $bMainAccount = true): Account
{
$aCredentials = $this->resolveLoginCredentials($sEmail, $oPassword);
$aCredentials = $this->resolveLoginCredentials(new Email($sEmail), $oPassword);
if (!\str_contains($aCredentials['email'], '@') || !\strlen($oPassword)) {
throw new ClientException(Notifications::InvalidInputArgument);
@ -184,14 +186,14 @@ trait UserAuth
return $oAccount;
}
public function switchAccount(string $sEmail) : bool
public function switchAccount(Email $oEmail): bool
{
$sEmail = $oEmail->GetEmail();
$this->Http()->ServerNoCache();
$oMainAccount = $this->getMainAccountFromToken(false);
if ($sEmail && $oMainAccount && $this->GetCapa(Capa::ADDITIONAL_ACCOUNTS)) {
$oAccount = null;
if ($oMainAccount->Email() !== $sEmail) {
$sEmail = \SnappyMail\IDN::emailToAscii($sEmail);
if ($oMainAccount->EmailAscii() !== $sEmail) {
$aAccounts = $this->GetAccounts($oMainAccount);
if (!isset($aAccounts[$sEmail])) {
throw new ClientException(Notifications::AccountDoesNotExist);

View file

@ -28,6 +28,16 @@ abstract class Account implements \JsonSerializable
return $this->sEmail;
}
public function EmailAscii(): string
{
return \SnappyMail\IDN::emailToAscii($this->sEmail);
}
public function EmailUtf8(): string
{
return \SnappyMail\IDN::emailToUtf8($this->sEmail);
}
public function Name(): string
{
return $this->sName;

View file

@ -1022,7 +1022,7 @@ class PdoAddressBook
$aEmailsToCreate = \array_filter($aEmailsObjects, function ($oItem) use ($aExists, &$aEmailsToUpdate) {
if ($oItem) {
$sEmail = \trim($oItem->GetEmail(true));
$sEmail = $oItem->GetEmailUtf8();
if (\strlen($sEmail)) {
$aEmailsToUpdate[] = $sEmail;
return !\in_array(\mb_strtolower($sEmail), $aExists);
@ -1033,7 +1033,7 @@ class PdoAddressBook
} else {
foreach ($aEmailsObjects as $oItem) {
if ($oItem) {
$sEmailUpdate = \trim($oItem->GetEmail(true));
$sEmailUpdate = $oItem->GetEmailUtf8();
if (\strlen($sEmailUpdate)) {
$aEmailsToUpdate[] = $sEmailUpdate;
}
@ -1048,7 +1048,7 @@ class PdoAddressBook
$oVCard = new VCard;
$bValid = false;
if ('' !== \trim($oEmail->GetEmail())) {
$oVCard->add('EMAIL', \trim($oEmail->GetEmail(true)));
$oVCard->add('EMAIL', $oEmail->GetEmailUtf8());
$bValid = true;
}
if ('' !== \trim($oEmail->GetDisplayName())) {