diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index 4db46dfe7..35674b06d 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -110,9 +110,9 @@ class ImapClient extends \MailSo\Net\NetClient return $this; } - if (!empty($oSettings->ProxyAuthUser) && !empty($oSettings->ProxyAuthPassword)) { + if (!empty($oSettings->ProxyAuthUser) && $oSettings->ProxyAuthPassword) { $sLogin = $oSettings->ProxyAuthUser; - $sPassword = $oSettings->ProxyAuthPassword; + $sPassword = $oSettings->ProxyAuthPassword->getValue(); $sProxyAuthUser = $oSettings->Login; } else { $sLogin = $oSettings->Login; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Log/Inherit.php b/snappymail/v/0.0.0/app/libraries/MailSo/Log/Inherit.php index 521a1b641..a82d0b2a0 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Log/Inherit.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Log/Inherit.php @@ -40,7 +40,10 @@ trait Inherit $this->oLogger && $this->oLogger->WriteException($oException, $iType, $sName); } - public function logMask(string $sWord): void + public function logMask( + #[\SensitiveParameter] + string $sWord + ): void { $this->oLogger && $this->oLogger->AddSecret($sWord); } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Log/Logger.php b/snappymail/v/0.0.0/app/libraries/MailSo/Log/Logger.php index f447d1f72..f6aa4f608 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Log/Logger.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Log/Logger.php @@ -107,7 +107,10 @@ class Logger extends \SplFixedArray return 0 < $this->count(); } - public function AddSecret(string $sWord) : void + public function AddSecret( + #[\SensitiveParameter] + string $sWord + ) : void { // $this->bShowSecrets && $this->Write("AddSecret '{$sWord}'", \LOG_INFO, '', false); $sWord = \trim($sWord); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Net/ConnectSettings.php b/snappymail/v/0.0.0/app/libraries/MailSo/Net/ConnectSettings.php index f37c3cca3..f706b99e3 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Net/ConnectSettings.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Net/ConnectSettings.php @@ -11,6 +11,8 @@ namespace MailSo\Net; +use SnappyMail\SensitiveString; + /** * @category MailSo * @package Net @@ -47,15 +49,29 @@ class ConnectSettings implements \JsonSerializable 'LOGIN' ]; public string $Login = ''; - public string $Password = ''; + private ?SensitiveString $Password = null; public string $ProxyAuthUser = ''; - public string $ProxyAuthPassword = ''; + public ?SensitiveString $ProxyAuthPassword = null; public function __construct() { $this->ssl = new SSLContext; } + public function __get(string $name) + { + if ('Password' === $name) { + return $this->Password ? $this->Password->getValue() : ''; + } + } + + public function __set(string $name, $value) + { + if ('Password' === $name) { + $this->Password = \is_string($value) ? new SensitiveString($value) : $value; + } + } + public static function Host() : string { return \SnappyMail\IDN::toAscii($this->host); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php index 54aab32d2..26b73bb16 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php @@ -44,9 +44,9 @@ abstract class Account implements \JsonSerializable : $this->sLogin; } - public function IncPassword() : SensitiveString + public function IncPassword() : string { - return $this->sPassword; + return $this->sPassword ? $this->sPassword->getValue() : ''; } public function OutLogin() : string @@ -103,30 +103,31 @@ abstract class Account implements \JsonSerializable public function jsonSerialize() { $result = [ -// 'account', // 0 - 'email' => $this->sEmail, // 1 - 'login' => $this->sLogin, // 2 - 'pass' => $this->sPassword, // 3 -// '', // 4 sClientCert + 'email' => $this->sEmail, + 'login' => $this->sLogin, + 'pass' => $this->IncPassword(), 'name' => $this->sName ]; if ($this->sSmtpLogin && $this->sSmtpPassword) { $result['smtp'] = [ 'user' => $this->sSmtpLogin, - 'pass' => $this->sSmtpPassword + 'pass' => $this->sSmtpPassword->getValue() ]; } if ($this->sProxyAuthUser && $this->sProxyAuthPassword) { $result['proxy'] = [ - 'user' => $this->sProxyAuthUser, // 5 - 'pass' => $this->sProxyAuthPassword // 6 + 'user' => $this->sProxyAuthUser, + 'pass' => $this->sProxyAuthPassword->getValue() ]; } return $result; } public static function NewInstanceFromCredentials(\RainLoop\Actions $oActions, - string $sEmail, string $sLogin, string $sPassword, bool $bThrowException = false): ?self + string $sEmail, string $sLogin, + #[\SensitiveParameter] + string $sPassword, + bool $bThrowException = false): ?self { $oAccount = null; if ($sEmail && $sLogin && $sPassword) { @@ -200,7 +201,7 @@ abstract class Account implements \JsonSerializable if (isset($aAccountHash['name'])) { $oAccount->sName = $aAccountHash['name']; } - $oActions->logMask($oAccount->sPassword); + $oActions->logMask($oAccount->IncPassword()); // init smtp user/password if (isset($aAccountHash['smtp'])) { $oAccount->sSmtpLogin = $aAccountHash['smtp']['user']; @@ -218,11 +219,6 @@ abstract class Account implements \JsonSerializable return $oAccount; } - // Deprecated - public function ImapConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Imap\ImapClient $oImapClient, \RainLoop\Config\Application $oConfig) : bool - { - return $this->ImapConnectAndLogin($oPlugins, $oImapClient, $oConfig); - } public function ImapConnectAndLogin(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Imap\ImapClient $oImapClient, \RainLoop\Config\Application $oConfig) : bool { $oSettings = $this->Domain()->ImapSettings(); @@ -300,7 +296,7 @@ abstract class Account implements \JsonSerializable */ $oSettings = $oClient->Settings; $oSettings->ProxyAuthUser = $this->sProxyAuthUser; - $oSettings->ProxyAuthPassword = $this->sProxyAuthPassword ?: ''; + $oSettings->ProxyAuthPassword = $this->sProxyAuthPassword; $client_name = \strtolower($oClient->getLogName()); diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php b/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php index 8028bd251..c58905ee6 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php @@ -43,7 +43,10 @@ abstract class Crypt /** * When $key is empty, it will use the smctoken. */ - private static function Passphrase(?string $key) : string + private static function Passphrase( + #[\SensitiveParameter] + ?string $key + ) : string { if (!$key) { if (empty($_COOKIE['smctoken'])) { @@ -55,7 +58,10 @@ abstract class Crypt return \sha1($key . APP_SALT, true); } - public static function Decrypt(array $data, string $key = null) /* : mixed */ + public static function Decrypt(array $data, + #[\SensitiveParameter] + string $key = null + ) /* : mixed */ { if (3 === \count($data) && isset($data[0], $data[1], $data[2]) && \strlen($data[0])) { try { @@ -75,7 +81,10 @@ abstract class Crypt } } - public static function DecryptFromJSON(string $data, string $key = null) /* : mixed */ + public static function DecryptFromJSON(string $data, + #[\SensitiveParameter] + string $key = null + ) /* : mixed */ { $data = static::jsonDecode($data); if (!\is_array($data)) { @@ -85,7 +94,10 @@ abstract class Crypt return static::Decrypt(\array_map('base64_decode', $data), $key); } - public static function DecryptUrlSafe(string $data, string $key = null) /* : mixed */ + public static function DecryptUrlSafe(string $data, + #[\SensitiveParameter] + string $key = null + ) /* : mixed */ { $data = \explode('.', $data); if (!\is_array($data)) { @@ -95,7 +107,12 @@ abstract class Crypt return static::Decrypt(\array_map('MailSo\\Base\\Utils::UrlSafeBase64Decode', $data), $key); } - public static function Encrypt($data, string $key = null) : array + public static function Encrypt( + #[\SensitiveParameter] + $data, + #[\SensitiveParameter] + string $key = null + ) : array { $data = \json_encode($data); @@ -128,17 +145,30 @@ abstract class Crypt */ } - public static function EncryptToJSON($data, string $key = null) : string + public static function EncryptToJSON( + #[\SensitiveParameter] + $data, + #[\SensitiveParameter] + string $key = null + ) : string { return \json_encode(\array_map('base64_encode', static::Encrypt($data, $key))); } - public static function EncryptUrlSafe($data, string $key = null) : string + public static function EncryptUrlSafe( + #[\SensitiveParameter] + $data, + #[\SensitiveParameter] + string $key = null + ) : string { return \implode('.', \array_map('MailSo\\Base\\Utils::UrlSafeBase64Encode', static::Encrypt($data, $key))); } - public static function SodiumDecrypt(string $data, string $nonce, string $key = null) /* : string|false */ + public static function SodiumDecrypt(string $data, string $nonce, + #[\SensitiveParameter] + string $key = null + ) /* : string|false */ { if (!\is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) { throw new \Exception('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt not callable'); @@ -151,7 +181,13 @@ abstract class Crypt ); } - public static function SodiumEncrypt(string $data, string $nonce, string $key = null) : string + public static function SodiumEncrypt( + #[\SensitiveParameter] + string $data, + string $nonce, + #[\SensitiveParameter] + string $key = null + ) : string { if (!\is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) { throw new \Exception('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt not callable'); @@ -168,7 +204,10 @@ abstract class Crypt return $result; } - public static function OpenSSLDecrypt(string $data, string $iv, string $key = null) /* : string|false */ + public static function OpenSSLDecrypt(string $data, string $iv, + #[\SensitiveParameter] + string $key = null + ) /* : string|false */ { if (!$data || !$iv) { throw new \InvalidArgumentException('$data or $iv is empty string'); @@ -189,7 +228,13 @@ abstract class Crypt ); } - public static function OpenSSLEncrypt(string $data, string $iv, string $key = null) : string + public static function OpenSSLEncrypt( + #[\SensitiveParameter] + string $data, + string $iv, + #[\SensitiveParameter] + string $key = null + ) : string { if (!$data || !$iv) { throw new \InvalidArgumentException('$data or $iv is empty string'); @@ -214,7 +259,10 @@ abstract class Crypt return $result; } - public static function XxteaDecrypt(string $data, string $salt, string $key = null) /* : mixed */ + public static function XxteaDecrypt(string $data, string $salt, + #[\SensitiveParameter] + string $key = null + ) /* : mixed */ { if (!$data || !$salt) { throw new \InvalidArgumentException('$data or $salt is empty string'); @@ -225,7 +273,13 @@ abstract class Crypt : \MailSo\Base\Xxtea::decrypt($data, $key); } - public static function XxteaEncrypt(string $data, string $salt, string $key = null) : string + public static function XxteaEncrypt( + #[\SensitiveParameter] + string $data, + string $salt, + #[\SensitiveParameter] + string $key = null + ) : string { if (!$data || !$salt) { throw new \InvalidArgumentException('$data or $salt is empty string'); diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/login.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/login.php index b0d0178c5..2f0441fcb 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/login.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/login.php @@ -2,10 +2,12 @@ namespace SnappyMail\SASL; +use SnappyMail\SensitiveString; + class Login extends \SnappyMail\SASL { protected - $passphrase; + SensitiveString $passphrase; public function authenticate(string $username, #[\SensitiveParameter] @@ -17,7 +19,7 @@ class Login extends \SnappyMail\SASL if ($challenge && !\str_starts_with($this->decode($challenge), 'Username:')) { throw new \Exception("Invalid response: {$this->decode($challenge)}"); } - $this->passphrase = $passphrase; + $this->passphrase = new SensitiveString($passphrase); return $this->encode($username); } @@ -27,7 +29,7 @@ class Login extends \SnappyMail\SASL if ($challenge && 'Password:' !== $this->decode($challenge)) { throw new \Exception("invalid response: {$challenge}"); } - return $this->encode($this->passphrase); + return $this->encode($this->passphrase->getValue()); } public static function isSupported(string $param) : bool diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauthbearer.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauthbearer.php index 412944f84..e6e8dc1a2 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauthbearer.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauthbearer.php @@ -4,7 +4,6 @@ * https://developers.google.com/gmail/imap/xoauth2-protocol */ - namespace SnappyMail\SASL; class OAuthBearer extends \SnappyMail\SASL diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/scram.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/scram.php index aba911cbc..10e824741 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/scram.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/scram.php @@ -4,16 +4,16 @@ * https://tools.ietf.org/html/rfc7677 */ - namespace SnappyMail\SASL; +use SnappyMail\SensitiveString; + class Scram extends \SnappyMail\SASL { - + protected ?SensitiveString $passphrase; protected $algo, $nonce, - $passphrase, $gs2_header, $auth_message, $server_key; @@ -41,7 +41,7 @@ class Scram extends \SnappyMail\SASL $authcid = \str_replace(array('=',','), array('=3D','=2C'), $authcid); $this->nonce = \bin2hex(\random_bytes(16)); - $this->passphrase = $passphrase; + $this->passphrase = new SensitiveString($passphrase); $this->gs2_header = 'n,' . (empty($authzid) ? '' : 'a=' . $authzid) . ','; $this->auth_message = "n={$authcid},r={$this->nonce}"; return $this->encode($this->gs2_header . $this->auth_message); @@ -71,7 +71,7 @@ class Scram extends \SnappyMail\SASL throw new \Exception('Server invalid salt'); } - $pass = \hash_pbkdf2($this->algo, $this->passphrase, $salt, \intval($values['i']), 0, true); + $pass = \hash_pbkdf2($this->algo, $this->passphrase->getValue(), $salt, \intval($values['i']), 0, true); $this->passphrase = null; $ckey = \hash_hmac($this->algo, 'Client Key', $pass, true); diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/xoauth2.php b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/xoauth2.php index 6a3462e8f..48eb3fa40 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sasl/xoauth2.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sasl/xoauth2.php @@ -4,7 +4,6 @@ * https://developers.google.com/gmail/imap/xoauth2-protocol */ - namespace SnappyMail\SASL; class XOAuth2 extends \SnappyMail\SASL diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/sensitivestring.php b/snappymail/v/0.0.0/app/libraries/snappymail/sensitivestring.php index 8755f06fc..449215c1d 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/sensitivestring.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/sensitivestring.php @@ -20,11 +20,22 @@ class SensitiveString /* extends SensitiveParameterValue | SensitiveParameter */ { private string $value, $nonce; - public function __construct(string $value) + public function __construct( + #[\SensitiveParameter] + string $value + ) { $this->setValue($value); } + public function getValue(): string + { + if (\is_callable('sodium_crypto_secretbox')) { + return \sodium_crypto_secretbox_open($this->value, $this->nonce, APP_SALT); + } + return xorIt($this->value); + } + public function setValue( #[\SensitiveParameter] string $value @@ -39,11 +50,23 @@ class SensitiveString /* extends SensitiveParameterValue | SensitiveParameter */ } } - public function __toString() : string + public function __toString(): string { - if (\is_callable('sodium_crypto_secretbox')) { - return \sodium_crypto_secretbox_open($this->value, $this->nonce, APP_SALT); - } - return xorIt($this->value); + return $this->getValue(); + } + + public function __debugInfo(): array + { + return []; + } + + public function __serialize(): array + { + throw new \Exception("Serialization of 'SensitiveString' is not allowed"); + } + + public function __unserialize(array $data): void + { + throw new \Exception("Unserialization of 'SensitiveString' is not allowed"); } }