Make better use of SnappyMail\SensitiveString

This commit is contained in:
the-djmaze 2024-02-27 11:03:36 +01:00
parent 0f7505baba
commit 7cacc9b503
18 changed files with 84 additions and 147 deletions

View file

@ -91,7 +91,6 @@ class SnappyMailHelper
*/ */
if ($doLogin && $aCredentials[1] && $aCredentials[2]) { if ($doLogin && $aCredentials[1] && $aCredentials[2]) {
try { try {
$oActions->Logger()->AddSecret($aCredentials[2]);
$oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2]); $oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2]);
if ($oAccount) { if ($oAccount) {
// Must be here due to bug #1241 // Must be here due to bug #1241
@ -202,9 +201,10 @@ class SnappyMailHelper
return \SnappyMail\Crypt::EncryptUrlSafe($sPassword, $sSalt); return \SnappyMail\Crypt::EncryptUrlSafe($sPassword, $sSalt);
} }
public static function decodePassword(string $sPassword, string $sSalt)/* : mixed */ public static function decodePassword(string $sPassword, string $sSalt) : ?\SnappyMail\SensitiveString
{ {
static::loadApp(); static::loadApp();
return \SnappyMail\Crypt::DecryptUrlSafe($sPassword, $sSalt); $result = \SnappyMail\Crypt::DecryptUrlSafe($sPassword, $sSalt);
return $result ? new \SnappyMail\SensitiveString($result) : $result;
} }
} }

View file

@ -81,7 +81,7 @@ trait Accounts
$aAccounts = $this->GetAccounts($oMainAccount); $aAccounts = $this->GetAccounts($oMainAccount);
$sEmail = \trim($this->GetActionParam('email', '')); $sEmail = \trim($this->GetActionParam('email', ''));
$sPassword = $this->GetActionParam('password', ''); $oPassword = new \SnappyMail\SensitiveString($this->GetActionParam('password', ''));
$sName = \trim($this->GetActionParam('name', '')); $sName = \trim($this->GetActionParam('name', ''));
$bNew = !empty($this->GetActionParam('new', 1)); $bNew = !empty($this->GetActionParam('new', 1));
@ -92,8 +92,8 @@ trait Accounts
throw new ClientException(Notifications::AccountDoesNotExist); throw new ClientException(Notifications::AccountDoesNotExist);
} }
if ($bNew || $sPassword) { if ($bNew || \strlen($oPassword)) {
$oNewAccount = $this->LoginProcess($sEmail, $sPassword, false); $oNewAccount = $this->LoginProcess($sEmail, $oPassword, false);
$aAccounts[$sEmail] = $oNewAccount->asTokenArray($oMainAccount); $aAccounts[$sEmail] = $oNewAccount->asTokenArray($oMainAccount);
} else { } else {
$aAccounts[$sEmail] = \RainLoop\Model\AdditionalAccount::convertArray($aAccounts[$sEmail]); $aAccounts[$sEmail] = \RainLoop\Model\AdditionalAccount::convertArray($aAccounts[$sEmail]);

View file

@ -60,9 +60,9 @@ trait AdminDomains
public function DoAdminDomainMatch() : array public function DoAdminDomainMatch() : array
{ {
$sEmail = $this->GetActionParam('username'); $sEmail = $this->GetActionParam('username');
$sPassword = '********'; $oPassword = new \SnappyMail\SensitiveString('********');
$sLogin = ''; $sLogin = '';
$this->resolveLoginCredentials($sEmail, $sPassword, $sLogin); $this->resolveLoginCredentials($sEmail, $oPassword, $sLogin);
$oDomain = \str_contains($sEmail, '@') $oDomain = \str_contains($sEmail, '@')
? $this->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true) ? $this->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true)
: null; : null;

View file

@ -1065,8 +1065,7 @@ trait Messages
} }
} }
$sPassphrase = $this->GetActionParam('signPassphrase', ''); $oPassphrase = new \SnappyMail\SensitiveString($this->GetActionParam('signPassphrase', ''));
$this->logMask($sPassphrase);
$sFingerprint = $this->GetActionParam('signFingerprint', ''); $sFingerprint = $this->GetActionParam('signFingerprint', '');
if ($sFingerprint) { if ($sFingerprint) {
@ -1084,7 +1083,7 @@ trait Messages
$oMessage->SubParts->Clear(); $oMessage->SubParts->Clear();
$oMessage->Attachments()->Clear(); $oMessage->Attachments()->Clear();
$GPG->addSignKey($sFingerprint, $sPassphrase); $GPG->addSignKey($sFingerprint, $oPassphrase);
$GPG->setsignmode(GNUPG_SIG_MODE_DETACH); $GPG->setsignmode(GNUPG_SIG_MODE_DETACH);
$sSignature = $GPG->signStream($fp); $sSignature = $GPG->signStream($fp);
if (!$sSignature) { if (!$sSignature) {
@ -1127,7 +1126,7 @@ trait Messages
$SMIME = $this->SMIME(); $SMIME = $this->SMIME();
$SMIME->setCertificate($sCertificate); $SMIME->setCertificate($sCertificate);
$SMIME->setPrivateKey($sPrivateKey, $sPassphrase); $SMIME->setPrivateKey($sPrivateKey, $oPassphrase);
$sSignature = $SMIME->sign($tmp, $detached); $sSignature = $SMIME->sign($tmp, $detached);
if (!$sSignature) { if (!$sSignature) {

View file

@ -113,10 +113,9 @@ trait Pgp
return $this->FalseResponse(); return $this->FalseResponse();
} }
$sPassphrase = $this->GetActionParam('passphrase', ''); $oPassphrase = new \SnappyMail\SensitiveString($this->GetActionParam('passphrase', ''));
$this->logMask($sPassphrase);
$GPG->addDecryptKey($this->GetActionParam('keyId', ''), $sPassphrase); $GPG->addDecryptKey($this->GetActionParam('keyId', ''), $oPassphrase);
$sData = $this->GetActionParam('data', ''); $sData = $this->GetActionParam('data', '');
$oPart = null; $oPart = null;
@ -160,12 +159,13 @@ trait Pgp
public function DoGnupgExportKey() : array public function DoGnupgExportKey() : array
{ {
$sPassphrase = $this->GetActionParam('passphrase', ''); $oPassphrase = $this->GetActionParam('isPrivate', '')
$this->logMask($sPassphrase); ? new \SnappyMail\SensitiveString($this->GetActionParam('passphrase', ''))
: null;
$GPG = $this->GnuPG(); $GPG = $this->GnuPG();
return $this->DefaultResponse($GPG ? $GPG->export( return $this->DefaultResponse($GPG ? $GPG->export(
$this->GetActionParam('keyId', ''), $this->GetActionParam('keyId', ''),
$sPassphrase $oPassphrase
) : false); ) : false);
} }
@ -176,11 +176,10 @@ trait Pgp
if ($GPG) { if ($GPG) {
$sName = $this->GetActionParam('name', ''); $sName = $this->GetActionParam('name', '');
$sEmail = $this->GetActionParam('email', ''); $sEmail = $this->GetActionParam('email', '');
$sPassphrase = $this->GetActionParam('passphrase', ''); $oPassphrase = new \SnappyMail\SensitiveString($this->GetActionParam('passphrase', ''));
$this->logMask($sPassphrase);
$fingerprint = $GPG->generateKey( $fingerprint = $GPG->generateKey(
$sName ? "{$sName} <{$sEmail}>" : $sEmail, $sName ? "{$sName} <{$sEmail}>" : $sEmail,
$sPassphrase $oPassphrase
); );
} }
return $this->DefaultResponse($fingerprint); return $this->DefaultResponse($fingerprint);

View file

@ -53,19 +53,18 @@ trait SMime
} }
/** /**
* Can be use by Identity * Can be used by Identity
*/ */
public function DoSMimeCreateCertificate() : array public function DoSMimeCreateCertificate() : array
{ {
$oAccount = $this->getAccountFromToken(); $oAccount = $this->getAccountFromToken();
$sPassphrase = $this->GetActionParam('passphrase', ''); $oPassphrase = new \SnappyMail\SensitiveString($this->GetActionParam('passphrase', ''));
$this->logMask($sPassphrase);
$cert = new Certificate(); $cert = new Certificate();
$cert->distinguishedName['commonName'] = $this->GetActionParam('name', '') ?: $oAccount->Name(); $cert->distinguishedName['commonName'] = $this->GetActionParam('name', '') ?: $oAccount->Name();
$cert->distinguishedName['emailAddress'] = $this->GetActionParam('email', '') ?: $oAccount->Email(); $cert->distinguishedName['emailAddress'] = $this->GetActionParam('email', '') ?: $oAccount->Email();
$result = $cert->createSelfSigned($sPassphrase, $this->GetActionParam('privateKey', '')); $result = $cert->createSelfSigned($oPassphrase, $this->GetActionParam('privateKey', ''));
return $this->DefaultResponse($result ?: false); return $this->DefaultResponse($result ?: false);
} }
@ -76,8 +75,7 @@ trait SMime
$sPartId = $this->GetActionParam('partId', ''); $sPartId = $this->GetActionParam('partId', '');
$sCertificate = $this->GetActionParam('certificate', ''); $sCertificate = $this->GetActionParam('certificate', '');
$sPrivateKey = $this->GetActionParam('privateKey', ''); $sPrivateKey = $this->GetActionParam('privateKey', '');
$sPassphrase = $this->GetActionParam('passphrase', ''); $oPassphrase = new \SnappyMail\SensitiveString($this->GetActionParam('passphrase', ''));
$this->logMask($sPassphrase);
$this->initMailClientConnection(); $this->initMailClientConnection();
$oImapClient = $this->ImapClient(); $oImapClient = $this->ImapClient();
@ -104,7 +102,7 @@ trait SMime
$SMIME = $this->SMIME(); $SMIME = $this->SMIME();
$SMIME->setCertificate($sCertificate); $SMIME->setCertificate($sCertificate);
$SMIME->setPrivateKey($sPrivateKey, $sPassphrase); $SMIME->setPrivateKey($sPrivateKey, $oPassphrase);
$result = $SMIME->decrypt($sBody); $result = $SMIME->decrypt($sBody);
return $this->DefaultResponse($result ?: false); return $this->DefaultResponse($result ?: false);

View file

@ -36,10 +36,10 @@ trait User
public function DoLogin() : array public function DoLogin() : array
{ {
$sEmail = \MailSo\Base\Utils::Trim($this->GetActionParam('Email', '')); $sEmail = \MailSo\Base\Utils::Trim($this->GetActionParam('Email', ''));
$sPassword = $this->GetActionParam('Password', ''); $oPassword = new \SnappyMail\SensitiveString($this->GetActionParam('Password', ''));
try { try {
$oAccount = $this->LoginProcess($sEmail, $sPassword); $oAccount = $this->LoginProcess($sEmail, $oPassword);
} catch (\Throwable $oException) { } catch (\Throwable $oException) {
$this->loginErrorDelay(); $this->loginErrorDelay();
throw $oException; throw $oException;

View file

@ -22,10 +22,7 @@ trait UserAuth
/** /**
* @throws \RainLoop\Exceptions\ClientException * @throws \RainLoop\Exceptions\ClientException
*/ */
public function resolveLoginCredentials(string &$sEmail, public function resolveLoginCredentials(string &$sEmail, \SnappyMail\SensitiveString $oPassword, string &$sLogin): void
#[\SensitiveParameter]
string &$sPassword,
string &$sLogin): void
{ {
$sEmail = \MailSo\Base\Utils::Trim($sEmail); $sEmail = \MailSo\Base\Utils::Trim($sEmail);
if ($this->Config()->Get('login', 'login_lowercase', true)) { if ($this->Config()->Get('login', 'login_lowercase', true)) {
@ -101,43 +98,40 @@ trait UserAuth
} }
} }
$sPassword = (string) $oPassword;
$this->Plugins()->RunHook('login.credentials.step-2', array(&$sEmail, &$sPassword)); $this->Plugins()->RunHook('login.credentials.step-2', array(&$sEmail, &$sPassword));
$this->logMask($sPassword);
$sLogin = $sEmail; $sLogin = $sEmail;
if ($this->Config()->Get('login', 'login_lowercase', true)) { if ($this->Config()->Get('login', 'login_lowercase', true)) {
$sLogin = \mb_strtolower($sLogin); $sLogin = \mb_strtolower($sLogin);
} }
$this->logMask($sPassword);
$this->Plugins()->RunHook('login.credentials', array(&$sEmail, &$sLogin, &$sPassword)); $this->Plugins()->RunHook('login.credentials', array(&$sEmail, &$sLogin, &$sPassword));
$this->logMask($sPassword); $this->logMask($sPassword);
$oPassword->setValue($sPassword);
} }
/** /**
* @throws \RainLoop\Exceptions\ClientException * @throws \RainLoop\Exceptions\ClientException
*/ */
public function LoginProcess(string &$sEmail, public function LoginProcess(string &$sEmail, \SnappyMail\SensitiveString $oPassword, bool $bMainAccount = true): Account
#[\SensitiveParameter]
string &$sPassword,
bool $bMainAccount = true
): Account
{ {
$sInputEmail = $sEmail; $sInputEmail = $sEmail;
$this->logMask($sPassword);
$sLogin = ''; $sLogin = '';
$this->resolveLoginCredentials($sEmail, $sPassword, $sLogin); $this->resolveLoginCredentials($sEmail, $oPassword, $sLogin);
if (!\str_contains($sEmail, '@') || !\strlen($sPassword)) { if (!\str_contains($sEmail, '@') || !\strlen($oPassword)) {
throw new ClientException(Notifications::InvalidInputArgument); throw new ClientException(Notifications::InvalidInputArgument);
} }
$oAccount = null; $oAccount = null;
try { try {
$oAccount = $bMainAccount $oAccount = $bMainAccount
? MainAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $sPassword, true) ? MainAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $oPassword, true)
: AdditionalAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $sPassword, true); : AdditionalAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $oPassword, true);
if (!$oAccount) { if (!$oAccount) {
throw new ClientException(Notifications::AuthError); throw new ClientException(Notifications::AuthError);
} }

View file

@ -111,17 +111,15 @@ class ActionsAdmin extends Actions
public function DoAdminLogin() : array public function DoAdminLogin() : array
{ {
$sLogin = trim($this->GetActionParam('Login', '')); $sLogin = trim($this->GetActionParam('Login', ''));
$sPassword = $this->GetActionParam('Password', ''); $oPassword = new \SnappyMail\SensitiveString($this->GetActionParam('Password', ''));
$this->logMask($sPassword);
$totp = $this->Config()->Get('security', 'admin_totp', ''); $totp = $this->Config()->Get('security', 'admin_totp', '');
// \explode(':',`getent shadow root`)[1]; // \explode(':',`getent shadow root`)[1];
if (!\strlen($sLogin) || !\strlen($sPassword) || if (!\strlen($sLogin) || !\strlen($oPassword) ||
!$this->Config()->Get('security', 'allow_admin_panel', true) || !$this->Config()->Get('security', 'allow_admin_panel', true) ||
$sLogin !== $this->Config()->Get('security', 'admin_login', '') || $sLogin !== $this->Config()->Get('security', 'admin_login', '') ||
!$this->Config()->ValidatePassword($sPassword) !$this->Config()->ValidatePassword($oPassword)
|| ($totp && !\SnappyMail\TOTP::Verify($totp, $this->GetActionParam('TOTP', '')))) || ($totp && !\SnappyMail\TOTP::Verify($totp, $this->GetActionParam('TOTP', ''))))
{ {
$this->LoggerAuthHelper(null, $this->getAdditionalLogParamsByUserLogin($sLogin, true), true); $this->LoggerAuthHelper(null, $this->getAdditionalLogParamsByUserLogin($sLogin, true), true);
@ -183,17 +181,13 @@ class ActionsAdmin extends Actions
$bResult = false; $bResult = false;
$oConfig = $this->Config(); $oConfig = $this->Config();
$sPassword = $this->GetActionParam('Password', ''); $oPassword = new \SnappyMail\SensitiveString($this->GetActionParam('Password', ''));
$this->logMask($sPassword);
$sNewPassword = $this->GetActionParam('newPassword', ''); $oNewPassword = new \SnappyMail\SensitiveString($this->GetActionParam('newPassword', ''));
if (\strlen($sNewPassword)) {
$this->logMask($sNewPassword);
}
$passfile = APP_PRIVATE_DATA.'admin_password.txt'; $passfile = APP_PRIVATE_DATA.'admin_password.txt';
if ($oConfig->ValidatePassword($sPassword)) { if ($oConfig->ValidatePassword($oPassword)) {
$sLogin = \trim($this->GetActionParam('Login', '')); $sLogin = \trim($this->GetActionParam('Login', ''));
if (\strlen($sLogin)) { if (\strlen($sLogin)) {
$oConfig->Set('security', 'admin_login', $sLogin); $oConfig->Set('security', 'admin_login', $sLogin);
@ -201,9 +195,9 @@ class ActionsAdmin extends Actions
$oConfig->Set('security', 'admin_totp', $this->GetActionParam('TOTP', '')); $oConfig->Set('security', 'admin_totp', $this->GetActionParam('TOTP', ''));
if (\strlen($sNewPassword)) { if (\strlen($oNewPassword)) {
$oConfig->SetPassword($sNewPassword); $oConfig->SetPassword($oNewPassword);
if (\is_file($passfile) && \trim(\file_get_contents($passfile)) !== $sNewPassword) { if (\is_file($passfile) && \trim(\file_get_contents($passfile)) !== (string) $oNewPassword) {
\unlink($passfile); \unlink($passfile);
} }
} }

View file

@ -120,25 +120,14 @@ class Application extends \RainLoop\Config\AbstractConfig
parent::Set($sSectionKey, $sParamKey, $mParamValue); parent::Set($sSectionKey, $sParamKey, $mParamValue);
} }
public function SetPassword( public function SetPassword(\SnappyMail\SensitiveString $oPassword) : void
#[\SensitiveParameter]
string $sPassword
) : void
{ {
$this->Set('security', 'admin_password', \password_hash($sPassword, PASSWORD_DEFAULT)); $this->Set('security', 'admin_password', \password_hash($oPassword, PASSWORD_DEFAULT));
} }
public function ValidatePassword( public function ValidatePassword(\SnappyMail\SensitiveString $oPassword) : bool
#[\SensitiveParameter]
string $sPassword
) : bool
{ {
$sConfigPassword = (string) $this->Get('security', 'admin_password', ''); return \strlen($oPassword) && \password_verify($oPassword, $this->Get('security', 'admin_password', ''));
if (32 == \strlen($sPassword) && \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword) {
$this->SetPassword($sPassword);
return true;
}
return \strlen($sPassword) && \password_verify($sPassword, $sConfigPassword);
} }
public function Save() : bool public function Save() : bool

View file

@ -15,7 +15,7 @@ abstract class Account implements \JsonSerializable
private string $sLogin = ''; private string $sLogin = '';
private ?SensitiveString $sPassword = null; private ?SensitiveString $oPassword = null;
private string $sSmtpLogin = ''; private string $sSmtpLogin = '';
@ -46,7 +46,7 @@ abstract class Account implements \JsonSerializable
public function IncPassword() : string public function IncPassword() : string
{ {
return $this->sPassword ? $this->sPassword->getValue() : ''; return $this->oPassword ? $this->oPassword->getValue() : '';
} }
public function OutLogin() : string public function OutLogin() : string
@ -66,16 +66,13 @@ abstract class Account implements \JsonSerializable
$this->sEmail, $this->sEmail,
$this->sLogin, $this->sLogin,
// \json_encode($this->Domain()), // \json_encode($this->Domain()),
// $this->sPassword // $this->oPassword
])); ]));
} }
public function SetPassword( public function SetPassword(SensitiveString $oPassword) : void
#[\SensitiveParameter]
string $sPassword
) : void
{ {
$this->sPassword = new SensitiveString($sPassword); $this->oPassword = $oPassword;
} }
public function SetSmtpPassword( public function SetSmtpPassword(
@ -125,12 +122,11 @@ abstract class Account implements \JsonSerializable
public static function NewInstanceFromCredentials(\RainLoop\Actions $oActions, public static function NewInstanceFromCredentials(\RainLoop\Actions $oActions,
string $sEmail, string $sLogin, string $sEmail, string $sLogin,
#[\SensitiveParameter] SensitiveString $oPassword,
string $sPassword,
bool $bThrowException = false): ?self bool $bThrowException = false): ?self
{ {
$oAccount = null; $oAccount = null;
if ($sEmail && $sLogin && $sPassword) { if ($sEmail && $sLogin && \strlen($oPassword)) {
$oDomain = $oActions->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true); $oDomain = $oActions->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true);
if ($oDomain) { if ($oDomain) {
if ($oDomain->ValidateWhiteList($sEmail, $sLogin)) { if ($oDomain->ValidateWhiteList($sEmail, $sLogin)) {
@ -138,7 +134,7 @@ abstract class Account implements \JsonSerializable
$oAccount->sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true); $oAccount->sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true);
$oAccount->sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin); $oAccount->sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin);
$oAccount->SetPassword($sPassword); $oAccount->SetPassword($oPassword);
$oAccount->oDomain = $oDomain; $oAccount->oDomain = $oDomain;
$oActions->Plugins()->RunHook('filter.account', array($oAccount)); $oActions->Plugins()->RunHook('filter.account', array($oAccount));
@ -194,25 +190,22 @@ abstract class Account implements \JsonSerializable
$oActions, $oActions,
$aAccountHash['email'], $aAccountHash['email'],
$aAccountHash['login'], $aAccountHash['login'],
$aAccountHash['pass'], new SensitiveString($aAccountHash['pass']),
$bThrowExceptionOnFalse $bThrowExceptionOnFalse
); );
if ($oAccount) { if ($oAccount) {
if (isset($aAccountHash['name'])) { if (isset($aAccountHash['name'])) {
$oAccount->sName = $aAccountHash['name']; $oAccount->sName = $aAccountHash['name'];
} }
$oActions->logMask($oAccount->IncPassword());
// init smtp user/password // init smtp user/password
if (isset($aAccountHash['smtp'])) { if (isset($aAccountHash['smtp'])) {
$oAccount->sSmtpLogin = $aAccountHash['smtp']['user']; $oAccount->sSmtpLogin = $aAccountHash['smtp']['user'];
$oAccount->SetSmtpPassword($aAccountHash['smtp']['pass']); $oAccount->SetSmtpPassword($aAccountHash['smtp']['pass']);
$oActions->logMask($oAccount->sSmtpPassword);
} }
// init proxy user/password // init proxy user/password
if (isset($aAccountHash['proxy'])) { if (isset($aAccountHash['proxy'])) {
$oAccount->sProxyAuthUser = $aAccountHash['proxy']['user']; $oAccount->sProxyAuthUser = $aAccountHash['proxy']['user'];
$oAccount->SetProxyAuthPassword($aAccountHash['proxy']['pass']); $oAccount->SetProxyAuthPassword($aAccountHash['proxy']['pass']);
$oActions->logMask($oAccount->sProxyAuthPassword);
} }
} }
} }
@ -240,7 +233,7 @@ abstract class Account implements \JsonSerializable
$oImapClient->Connect($oSettings); $oImapClient->Connect($oSettings);
$oPlugins->RunHook('imap.after-connect', array($this, $oImapClient, $oSettings)); $oPlugins->RunHook('imap.after-connect', array($this, $oImapClient, $oSettings));
$oSettings->Password = $this->sPassword; $oSettings->Password = $this->oPassword;
return $this->netClientLogin($oImapClient, $oPlugins); return $this->netClientLogin($oImapClient, $oPlugins);
} }
@ -264,7 +257,7 @@ abstract class Account implements \JsonSerializable
throw new RequireCredentialsException throw new RequireCredentialsException
} }
*/ */
$oSettings->Password = $this->sSmtpPassword ?: $this->sPassword; $oSettings->Password = $this->sSmtpPassword ?: $this->oPassword;
return $this->netClientLogin($oSmtpClient, $oPlugins); return $this->netClientLogin($oSmtpClient, $oPlugins);
} }
@ -279,7 +272,7 @@ abstract class Account implements \JsonSerializable
$oSieveClient->Connect($oSettings); $oSieveClient->Connect($oSettings);
$oPlugins->RunHook('sieve.after-connect', array($this, $oSieveClient, $oSettings)); $oPlugins->RunHook('sieve.after-connect', array($this, $oSieveClient, $oSettings));
$oSettings->Password = $this->sPassword; $oSettings->Password = $this->oPassword;
return $this->netClientLogin($oSieveClient, $oPlugins); return $this->netClientLogin($oSieveClient, $oPlugins);
} }

View file

@ -120,16 +120,6 @@ class ServiceActions
$aPost[$key] = '*******'; $aPost[$key] = '*******';
} }
} }
/*
switch ($sMethodName)
{
case 'DoLogin':
case 'DoAdminLogin':
case 'DoAccountAdd':
$this->oActions->logMask($this->oActions->GetActionParam('Password', ''));
break;
}
*/
$this->oActions->logWrite(Utils::jsonEncode($aPost), \LOG_INFO, 'POST'); $this->oActions->logWrite(Utils::jsonEncode($aPost), \LOG_INFO, 'POST');
} else if (3 < \count($this->aPaths) && $this->oHttp->IsGet()) { } else if (3 < \count($this->aPaths) && $this->oHttp->IsGet()) {
$this->oActions->SetActionParams(array( $this->oActions->SetActionParams(array(
@ -561,14 +551,14 @@ class ServiceActions
(0 === $aData['Time'] || \time() - 10 < $aData['Time'])) (0 === $aData['Time'] || \time() - 10 < $aData['Time']))
{ {
$sEmail = \trim($aData['Email']); $sEmail = \trim($aData['Email']);
$sPassword = $aData['Password']; $oPassword = new \SnappyMail\SensitiveString($aData['Password']);
$aAdditionalOptions = (isset($aData['AdditionalOptions']) && \is_array($aData['AdditionalOptions'])) $aAdditionalOptions = (isset($aData['AdditionalOptions']) && \is_array($aData['AdditionalOptions']))
? $aData['AdditionalOptions'] : []; ? $aData['AdditionalOptions'] : [];
try try
{ {
$oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); $oAccount = $this->oActions->LoginProcess($sEmail, $oPassword);
if ($aAdditionalOptions) { if ($aAdditionalOptions) {
$bNeedToSettings = false; $bNeedToSettings = false;

View file

@ -284,10 +284,7 @@ abstract class Base
/** /**
* Add a key for decryption * Add a key for decryption
*/ */
public function addDecryptKey(string $fingerprint, public function addDecryptKey(string $fingerprint, \SnappyMail\SensitiveString $passphrase) : bool
#[\SensitiveParameter]
string $passphrase
) : bool
{ {
$this->decryptKeys[$fingerprint] = $passphrase; $this->decryptKeys[$fingerprint] = $passphrase;
// $this->decryptKeys[\substr($fingerprint, -16)] = $passphrase; // $this->decryptKeys[\substr($fingerprint, -16)] = $passphrase;
@ -306,10 +303,7 @@ abstract class Base
/** /**
* Add a key for signing * Add a key for signing
*/ */
public function addSignKey(string $fingerprint, public function addSignKey(string $fingerprint, \SnappyMail\SensitiveString $passphrase) : bool
#[\SensitiveParameter]
string $passphrase
) : bool
{ {
$this->signKeys[$fingerprint] = $passphrase; $this->signKeys[$fingerprint] = $passphrase;
// $this->signKeys[\substr($fingerprint, -16)] = $passphrase; // $this->signKeys[\substr($fingerprint, -16)] = $passphrase;
@ -356,10 +350,7 @@ abstract class Base
]; ];
} }
public function addPassphrase($keyId, public function addPassphrase($keyId, \SnappyMail\SensitiveString $passphrase)
#[\SensitiveParameter]
$passphrase
)
{ {
$this->passphrases[$keyId] = $passphrase; $this->passphrases[$keyId] = $passphrase;
return $this; return $this;

View file

@ -95,7 +95,7 @@ class PGP extends Base
$fclose = $this->setOutput($output); $fclose = $this->setOutput($output);
if ($this->decryptKeys) { if ($this->decryptKeys) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->decryptKeys); $_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->decryptKeys));
} }
$result = $this->exec(['--decrypt','--skip-verify']); $result = $this->exec(['--decrypt','--skip-verify']);
@ -241,7 +241,7 @@ class PGP extends Base
throw new \Exception(($private ? 'Private' : 'Public') . ' key not found: ' . $keyId); throw new \Exception(($private ? 'Private' : 'Public') . ' key not found: ' . $keyId);
} }
if ($private && $this->passphrases) { if ($private && $this->passphrases) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->passphrases); $_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->passphrases));
} }
$result = $this->exec([ $result = $this->exec([
$private ? '--export-secret-keys' : '--export', $private ? '--export-secret-keys' : '--export',
@ -362,7 +362,7 @@ class PGP extends Base
$arguments = ['--import']; $arguments = ['--import'];
if ($this->passphrases) { if ($this->passphrases) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->passphrases); $_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->passphrases));
} else { } else {
$arguments[] = '--batch'; $arguments[] = '--batch';
} }
@ -629,7 +629,7 @@ class PGP extends Base
foreach ($this->signKeys as $fingerprint => $pass) { foreach ($this->signKeys as $fingerprint => $pass) {
$arguments[] = '--local-user ' . \escapeshellarg($fingerprint); $arguments[] = '--local-user ' . \escapeshellarg($fingerprint);
} }
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->signKeys); $_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->signKeys));
} }
$result = $this->exec($arguments); $result = $this->exec($arguments);

View file

@ -86,10 +86,7 @@ class GnuPG
/** /**
* Add a key for decryption * Add a key for decryption
*/ */
public function addDecryptKey(string $fingerprint, public function addDecryptKey(string $fingerprint, \SnappyMail\SensitiveString $passphrase) : bool
#[\SensitiveParameter]
string $passphrase
) : bool
{ {
return $this->handler()->adddecryptkey($fingerprint, $passphrase); return $this->handler()->adddecryptkey($fingerprint, $passphrase);
} }
@ -105,10 +102,7 @@ class GnuPG
/** /**
* Add a key for signing * Add a key for signing
*/ */
public function addSignKey(string $fingerprint, public function addSignKey(string $fingerprint, \SnappyMail\SensitiveString $passphrase) : bool
#[\SensitiveParameter]
?string $passphrase
) : bool
{ {
return $this->handler()->addsignkey($fingerprint, $passphrase); return $this->handler()->addsignkey($fingerprint, $passphrase);
} }
@ -226,10 +220,7 @@ class GnuPG
/** /**
* Exports a key * Exports a key
*/ */
public function export(string $fingerprint, public function export(string $fingerprint, ?\SnappyMail\SensitiveString $passphrase = null) /*: string|false*/
#[\SensitiveParameter]
string $passphrase = ''
) /*: string|false*/
{ {
if ($passphrase) { if ($passphrase) {
return $this->getGPG() return $this->getGPG()
@ -276,10 +267,7 @@ class GnuPG
/** /**
* Generates a key * Generates a key
*/ */
public function generateKey(string $uid, public function generateKey(string $uid, \SnappyMail\SensitiveString $passphrase) /*: string|false*/
#[\SensitiveParameter]
string $passphrase
) /*: string|false*/
{ {
$GPG = $this->getGPG(false); $GPG = $this->getGPG(false);
return $GPG ? $GPG->generateKey($uid, $passphrase) : false; return $GPG ? $GPG->generateKey($uid, $passphrase) : false;

View file

@ -2,7 +2,7 @@
namespace SnappyMail; namespace SnappyMail;
class SensitiveString /* extends SensitiveParameterValue | SensitiveParameter */ implements \Stringable class SensitiveString /* extends SensitiveParameterValue | SensitiveParameter */ implements \Stringable, \JsonSerializable
{ {
private string $value, $nonce; private string $value, $nonce;
private static ?string $key = null; private static ?string $key = null;
@ -28,6 +28,7 @@ class SensitiveString /* extends SensitiveParameterValue | SensitiveParameter */
string $value string $value
) : void ) : void
{ {
\strlen($value) && \RainLoop\Api::Actions()->logMask($value);
if (\is_callable('sodium_crypto_secretbox')) { if (\is_callable('sodium_crypto_secretbox')) {
$this->nonce = \random_bytes(\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); $this->nonce = \random_bytes(\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
if (!static::$key) { if (!static::$key) {
@ -60,6 +61,12 @@ class SensitiveString /* extends SensitiveParameterValue | SensitiveParameter */
return $this->getValue(); return $this->getValue();
} }
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
throw new \Exception("JSON serialization of 'SnappyMail\\SensitiveString' is not allowed");
}
public function __debugInfo(): array public function __debugInfo(): array
{ {
return []; return [];

View file

@ -112,11 +112,7 @@ class Certificate
return \openssl_get_cipher_methods($aliases); return \openssl_get_cipher_methods($aliases);
} }
public function createSelfSigned( public function createSelfSigned(\SnappyMail\SensitiveString $passphrase, ?string $privateKey = null) : array
#[\SensitiveParameter]
string $passphrase = '',
?string $privateKey = null
) : array
{ {
$options = array( $options = array(
'config' => __DIR__ . '/openssl.cnf', 'config' => __DIR__ . '/openssl.cnf',

View file

@ -132,8 +132,7 @@ class OpenSSL
} }
public function setPrivateKey(/*OpenSSLAsymmetricKey|string*/$privateKey, public function setPrivateKey(/*OpenSSLAsymmetricKey|string*/$privateKey,
#[\SensitiveParameter] ?\SnappyMail\SensitiveString $passphrase = null
?string $passphrase = null
) : void ) : void
{ {
$this->privateKey = \openssl_pkey_get_private($privateKey, $passphrase); $this->privateKey = \openssl_pkey_get_private($privateKey, $passphrase);