mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-27 02:59:21 +03:00
More improvements for #1343
This commit is contained in:
parent
13f8ab5caf
commit
f869ed5121
11 changed files with 148 additions and 53 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
* https://developers.google.com/gmail/imap/xoauth2-protocol
|
||||
*/
|
||||
|
||||
|
||||
namespace SnappyMail\SASL;
|
||||
|
||||
class OAuthBearer extends \SnappyMail\SASL
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
* https://developers.google.com/gmail/imap/xoauth2-protocol
|
||||
*/
|
||||
|
||||
|
||||
namespace SnappyMail\SASL;
|
||||
|
||||
class XOAuth2 extends \SnappyMail\SASL
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue