mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-11 00:14:50 +03:00
Improved Domain management code
This commit is contained in:
parent
de150b359c
commit
df7b11eadb
3 changed files with 104 additions and 136 deletions
|
|
@ -1 +1,5 @@
|
|||
outlook.com,qq.com,yahoo.com,gmail.com,hotmail.com
|
||||
outlook.com
|
||||
qq.com
|
||||
yahoo.com
|
||||
gmail.com
|
||||
hotmail.com
|
||||
|
|
|
|||
|
|
@ -165,14 +165,13 @@ abstract class Utils
|
|||
|| !\preg_match('/[^\x09\x10\x13\x0A\x0D\x20-\x7E]/', $sValue);
|
||||
}
|
||||
|
||||
public static function StrMailDomainToLower(string $sValue) : string
|
||||
private static function StrMailDomainToLower(string $sValue) : string
|
||||
{
|
||||
$aParts = \explode('@', $sValue);
|
||||
$iLast = \count($aParts) - 1;
|
||||
if ($iLast) {
|
||||
$iLast = \count($aParts) - 1;
|
||||
$aParts[$iLast] = \mb_strtolower($aParts[$iLast]);
|
||||
}
|
||||
|
||||
return \implode('@', $aParts);
|
||||
}
|
||||
|
||||
|
|
@ -704,7 +703,10 @@ abstract class Utils
|
|||
return !empty($sIp) && $sIp === \filter_var($sIp, FILTER_VALIDATE_IP);
|
||||
}
|
||||
|
||||
public static function IdnToUtf8(string $sStr, bool $bLowerIfAscii = false) : string
|
||||
/**
|
||||
* Converts xn--du8h.snappymail.eu to 📧.snappymail.eu
|
||||
*/
|
||||
public static function IdnToUtf8(string $sStr, bool $bLowerCase = false) : string
|
||||
{
|
||||
if (\strlen($sStr) && \preg_match('/(^|\.|@)xn--/i', $sStr)) {
|
||||
try
|
||||
|
|
@ -714,20 +716,19 @@ abstract class Utils
|
|||
catch (\Throwable $oException) {}
|
||||
}
|
||||
|
||||
return $bLowerIfAscii ? static::StrMailDomainToLower($sStr) : $sStr;
|
||||
return $bLowerCase ? static::StrMailDomainToLower($sStr) : $sStr;
|
||||
}
|
||||
|
||||
public static function IdnToAscii(string $sStr, bool $bLowerIfAscii = false) : string
|
||||
/**
|
||||
* Converts 📧.snappymail.eu to xn--du8h.snappymail.eu
|
||||
*/
|
||||
public static function IdnToAscii(string $sStr, bool $bLowerCase = false) : string
|
||||
{
|
||||
$sStr = $bLowerIfAscii ? static::StrMailDomainToLower($sStr) : $sStr;
|
||||
|
||||
$sUser = '';
|
||||
$sDomain = $sStr;
|
||||
if (false !== \strpos($sStr, '@')) {
|
||||
$sUser = static::GetAccountNameFromEmail($sStr);
|
||||
$sDomain = static::GetDomainFromEmail($sStr);
|
||||
$aParts = \explode('@', $sStr);
|
||||
$sDomain = \array_pop($aParts);
|
||||
if ($bLowerCase) {
|
||||
$sDomain = \mb_strtolower($sDomain);
|
||||
}
|
||||
|
||||
if (\strlen($sDomain) && \preg_match('/[^\x20-\x7E]/', $sDomain)) {
|
||||
try
|
||||
{
|
||||
|
|
@ -735,7 +736,7 @@ abstract class Utils
|
|||
}
|
||||
catch (\Throwable $oException) {}
|
||||
}
|
||||
|
||||
return ('' === $sUser ? '' : $sUser.'@').$sDomain;
|
||||
$aParts[] = $sDomain;
|
||||
return \implode('@', $aParts);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,48 +2,40 @@
|
|||
|
||||
namespace RainLoop\Providers\Domain;
|
||||
|
||||
use MailSo\Cache\CacheClient;
|
||||
|
||||
class DefaultDomain implements DomainInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sDomainPath;
|
||||
const CACHE_KEY = '/WildCard/DomainCache/';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Cache\CacheClient
|
||||
*/
|
||||
protected $oCacher;
|
||||
protected string $sDomainPath;
|
||||
|
||||
public function __construct(string $sDomainPath, ?\MailSo\Cache\CacheClient $oCacher = null)
|
||||
protected ?CacheClient $oCacher;
|
||||
|
||||
public function __construct(string $sDomainPath, ?CacheClient $oCacher = null)
|
||||
{
|
||||
$this->sDomainPath = \rtrim(\trim($sDomainPath), '\\/');
|
||||
$this->oCacher = $oCacher;
|
||||
}
|
||||
|
||||
private static function codeFileName(string $sName, bool $bBack = false) : string
|
||||
private static function decodeFileName(string $sName) : string
|
||||
{
|
||||
if ($bBack && 'default' === $sName) {
|
||||
return '*';
|
||||
}
|
||||
|
||||
if (!$bBack && '*' === $sName) {
|
||||
return 'default';
|
||||
}
|
||||
|
||||
return $bBack
|
||||
? \str_replace('_wildcard_', '*', \MailSo\Base\Utils::IdnToUtf8($sName, true))
|
||||
: \str_replace('*', '_wildcard_', \MailSo\Base\Utils::IdnToAscii($sName, true));
|
||||
return ('default' === $sName)
|
||||
? '*'
|
||||
: \str_replace('_wildcard_', '*', \MailSo\Base\Utils::IdnToUtf8($sName, true));
|
||||
}
|
||||
|
||||
private static function wildcardDomainsCacheKey() : string
|
||||
private static function encodeFileName(string $sName) : string
|
||||
{
|
||||
return '/WildCard/DomainCache/'.\md5(APP_VERSION.APP_PRIVATE_DATA_NAME).'/';
|
||||
return ('*' === $sName)
|
||||
? 'default'
|
||||
: \str_replace('*', '_wildcard_', \MailSo\Base\Utils::IdnToAscii($sName, true));
|
||||
}
|
||||
|
||||
private function getWildcardDomainsLine() : string
|
||||
{
|
||||
if ($this->oCacher) {
|
||||
$sResult = $this->oCacher->Get(static::wildcardDomainsCacheKey());
|
||||
$sResult = $this->oCacher->Get(static::CACHE_KEY);
|
||||
if (\strlen($sResult)) {
|
||||
return $sResult;
|
||||
}
|
||||
|
|
@ -56,14 +48,21 @@ class DefaultDomain implements DomainInterface
|
|||
foreach ($aList as $sFile) {
|
||||
$sName = \substr(\basename($sFile), 0, -5);
|
||||
if ('default' === $sName || false !== \strpos($sName, '_wildcard_')) {
|
||||
$aNames[] = static::codeFileName($sName, true);
|
||||
$aNames[] = static::decodeFileName($sName);
|
||||
}
|
||||
}
|
||||
$aList = \glob($this->sDomainPath.'/*.ini');
|
||||
foreach ($aList as $sFile) {
|
||||
$sName = \substr(\basename($sFile), 0, -4);
|
||||
if ('default' === $sName || false !== \strpos($sName, '_wildcard_')) {
|
||||
$aNames[] = static::codeFileName($sName, true);
|
||||
$aNames[] = static::decodeFileName($sName);
|
||||
}
|
||||
}
|
||||
$aList = \glob($this->sDomainPath.'/*.alias');
|
||||
foreach ($aList as $sFile) {
|
||||
$sName = \substr(\basename($sFile), 0, -6);
|
||||
if ('default' === $sName || false !== \strpos($sName, '_wildcard_')) {
|
||||
$aNames[] = static::decodeFileName($sName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +73,7 @@ class DefaultDomain implements DomainInterface
|
|||
}
|
||||
|
||||
if ($this->oCacher) {
|
||||
$this->oCacher->Set(static::wildcardDomainsCacheKey(), $sResult);
|
||||
$this->oCacher->Set(static::CACHE_KEY, $sResult);
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
|
|
@ -82,29 +81,24 @@ class DefaultDomain implements DomainInterface
|
|||
|
||||
public function Load(string $sName, bool $bFindWithWildCard = false, bool $bCheckDisabled = true, bool $bCheckAliases = true) : ?\RainLoop\Model\Domain
|
||||
{
|
||||
if ($bCheckDisabled) {
|
||||
$aDisabled = [];
|
||||
if (\file_exists($this->sDomainPath.'/disabled')) {
|
||||
$aDisabled = \explode(',', \file_get_contents($this->sDomainPath.'/disabled'));
|
||||
if ($aDisabled && \in_array(\MailSo\Base\Utils::IdnToAscii($sName, true), $aDisabled)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$sName = \MailSo\Base\Utils::IdnToUtf8($sName, true);
|
||||
if ($bCheckDisabled && \in_array($sName, $this->getDisabled())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$sRealFileName = static::codeFileName($sName);
|
||||
$sRealFileBase = $this->sDomainPath . '/' . static::encodeFileName($sName);
|
||||
|
||||
if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.json')) {
|
||||
$aDomain = \json_decode(\file_get_contents($this->sDomainPath.'/'.$sRealFileName.'.json'), true) ?: array();
|
||||
if (\file_exists($sRealFileBase.'.json')) {
|
||||
$aDomain = \json_decode(\file_get_contents($sRealFileBase.'.json'), true) ?: array();
|
||||
return \RainLoop\Model\Domain::fromArray($sName, $aDomain);
|
||||
}
|
||||
if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini')) {
|
||||
$aDomain = \parse_ini_file($this->sDomainPath.'/'.$sRealFileName.'.ini') ?: array();
|
||||
if (\file_exists($sRealFileBase.'.ini')) {
|
||||
$aDomain = \parse_ini_file($sRealFileBase.'.ini') ?: array();
|
||||
return \RainLoop\Model\Domain::fromIniArray($sName, $aDomain);
|
||||
}
|
||||
|
||||
if ($bCheckAliases && \file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias')) {
|
||||
$sAlias = \trim(\file_get_contents($this->sDomainPath.'/'.$sRealFileName.'.alias'));
|
||||
if ($bCheckAliases && \file_exists($sRealFileBase.'.alias')) {
|
||||
$sAlias = \trim(\file_get_contents($sRealFileBase.'.alias'));
|
||||
if (!empty($sAlias)) {
|
||||
$oDomain = $this->Load($sAlias, false, false, false);
|
||||
$oDomain && $oDomain->SetAliasName($sName);
|
||||
|
|
@ -116,10 +110,10 @@ class DefaultDomain implements DomainInterface
|
|||
$sNames = $this->getWildcardDomainsLine();
|
||||
$sFoundValue = '';
|
||||
if (\strlen($sNames)
|
||||
&& \RainLoop\Plugins\Helper::ValidateWildcardValues(\MailSo\Base\Utils::IdnToUtf8($sName, true), $sNames, $sFoundValue)
|
||||
&& \RainLoop\Plugins\Helper::ValidateWildcardValues($sName, $sNames, $sFoundValue)
|
||||
&& \strlen($sFoundValue)
|
||||
) {
|
||||
return $this->Load($sFoundValue, false);
|
||||
return $this->Load($sFoundValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,111 +122,80 @@ class DefaultDomain implements DomainInterface
|
|||
|
||||
public function Save(\RainLoop\Model\Domain $oDomain) : bool
|
||||
{
|
||||
$sRealFileName = static::codeFileName($oDomain->Name());
|
||||
|
||||
if ($this->oCacher)
|
||||
{
|
||||
$this->oCacher->Delete(static::wildcardDomainsCacheKey());
|
||||
}
|
||||
|
||||
$sRealFileName = static::encodeFileName($oDomain->Name());
|
||||
\RainLoop\Utils::saveFile($this->sDomainPath.'/'.$sRealFileName.'.json', \json_encode($oDomain, \JSON_PRETTY_PRINT));
|
||||
|
||||
$this->oCacher && $this->oCacher->Delete(static::CACHE_KEY);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function SaveAlias(string $sName, string $sAlias) : bool
|
||||
{
|
||||
$sRealFileName = static::codeFileName($sName);
|
||||
|
||||
if ($this->oCacher)
|
||||
{
|
||||
$this->oCacher->Delete(static::wildcardDomainsCacheKey());
|
||||
}
|
||||
|
||||
$sAlias = \MailSo\Base\Utils::IdnToUtf8($sAlias, true);
|
||||
$sRealFileName = static::encodeFileName($sName);
|
||||
\RainLoop\Utils::saveFile($this->sDomainPath.'/'.$sRealFileName.'.alias', $sAlias);
|
||||
$this->oCacher && $this->oCacher->Delete(static::CACHE_KEY);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getDisabled() : array
|
||||
{
|
||||
$sFile = '';
|
||||
if (\file_exists($this->sDomainPath.'/disabled')) {
|
||||
$sFile = \file_get_contents($this->sDomainPath.'/disabled');
|
||||
}
|
||||
$aDisabled = array();
|
||||
// RainLoop use comma, we use newline
|
||||
$sItem = \strtok($sFile, ",\n");
|
||||
while (false !== $sItem) {
|
||||
$aDisabled[] = \MailSo\Base\Utils::IdnToUtf8($sItem, true);
|
||||
$sItem = \strtok(",\n");
|
||||
}
|
||||
return $aDisabled;
|
||||
// return \array_unique($aDisabled);
|
||||
}
|
||||
|
||||
public function Disable(string $sName, bool $bDisable) : bool
|
||||
{
|
||||
$sName = \MailSo\Base\Utils::IdnToAscii($sName, true);
|
||||
|
||||
$sFile = '';
|
||||
if (\file_exists($this->sDomainPath.'/disabled'))
|
||||
{
|
||||
$sFile = \file_get_contents($this->sDomainPath.'/disabled');
|
||||
}
|
||||
|
||||
$aResult = array();
|
||||
$aNames = \explode(',', $sFile);
|
||||
if ($bDisable)
|
||||
{
|
||||
\array_push($aNames, $sName);
|
||||
$aResult = $aNames;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($aNames as $sItem)
|
||||
{
|
||||
if ($sName !== $sItem)
|
||||
{
|
||||
$aResult[] = $sItem;
|
||||
}
|
||||
$sName = \MailSo\Base\Utils::IdnToUtf8($sName, true);
|
||||
if ($sName) {
|
||||
$aResult = $this->getDisabled();
|
||||
if ($bDisable) {
|
||||
$aResult[] = $sName;
|
||||
} else {
|
||||
$aResult = \array_filter($aResult, fn($v) => $v !== $sName);
|
||||
}
|
||||
\RainLoop\Utils::saveFile($this->sDomainPath.'/disabled', \implode("\n", \array_unique($aResult)));
|
||||
}
|
||||
|
||||
\RainLoop\Utils::saveFile($this->sDomainPath.'/disabled', \trim(\implode(',', \array_unique($aResult)), ', '));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function Delete(string $sName) : bool
|
||||
{
|
||||
$bResult = true;
|
||||
$sRealFileName = static::codeFileName($sName);
|
||||
|
||||
if (\strlen($sName))
|
||||
{
|
||||
if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.json'))
|
||||
{
|
||||
$bResult = 0 < \strlen($sName);
|
||||
if ($bResult) {
|
||||
$sRealFileName = static::encodeFileName($sName);
|
||||
if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.json')) {
|
||||
$bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.json');
|
||||
}
|
||||
if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini'))
|
||||
{
|
||||
if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.ini')) {
|
||||
$bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.ini');
|
||||
}
|
||||
else if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias'))
|
||||
{
|
||||
if (\file_exists($this->sDomainPath.'/'.$sRealFileName.'.alias')) {
|
||||
$bResult = \unlink($this->sDomainPath.'/'.$sRealFileName.'.alias');
|
||||
}
|
||||
if ($bResult) {
|
||||
$this->Disable($sName, false);
|
||||
}
|
||||
if ($this->oCacher) {
|
||||
$this->oCacher->Delete(static::CACHE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
if ($bResult)
|
||||
{
|
||||
$this->Disable($sName, false);
|
||||
}
|
||||
|
||||
if ($this->oCacher)
|
||||
{
|
||||
$this->oCacher->Delete(static::wildcardDomainsCacheKey());
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
public function GetList(bool $bIncludeAliases = true) : array
|
||||
{
|
||||
$aDisabledNames = array();
|
||||
if (\file_exists($this->sDomainPath.'/disabled')) {
|
||||
$sDisabled = \file_get_contents($this->sDomainPath.'/disabled');
|
||||
if (\strlen($sDisabled)) {
|
||||
$aDisabledNames = \explode(',', $sDisabled);
|
||||
foreach ($aDisabledNames as &$sValue) {
|
||||
$sValue = \MailSo\Base\Utils::IdnToUtf8($sValue, true);
|
||||
}
|
||||
$aDisabledNames = \array_unique($aDisabledNames);
|
||||
}
|
||||
}
|
||||
|
||||
$aDisabledNames = $this->getDisabled();
|
||||
$aResult = array();
|
||||
$aWildCards = array();
|
||||
$aAliases = array();
|
||||
|
|
@ -242,7 +205,7 @@ class DefaultDomain implements DomainInterface
|
|||
foreach ($aList as $sFile) {
|
||||
$bAlias = '.alias' === \substr($sFile, -6);
|
||||
if ($bAlias || '.json' === \substr($sFile, -5) || '.ini' === \substr($sFile, -4)) {
|
||||
$sName = static::codeFileName(\preg_replace('/\.(ini|json|alias)$/', '', $sFile), true);
|
||||
$sName = static::decodeFileName(\preg_replace('/\.(ini|json|alias)$/', '', $sFile));
|
||||
if ($bAlias) {
|
||||
if ($bIncludeAliases) {
|
||||
$aAliases[$sName] = array(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue