mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-11-10 17:13:38 +08:00
More encrypt/decrypt improvements and fixes
This commit is contained in:
parent
59cb0978c7
commit
b1e895907f
6 changed files with 78 additions and 73 deletions
|
@ -73,7 +73,7 @@ trait Accounts
|
|||
|
||||
$oAccountToChange = null;
|
||||
if ($oAccount->Email() === $sEmailToDelete && !empty($aAccounts[$sParentEmail])) {
|
||||
$oAccountToChange = $this->GetAccountFromCustomToken($aAccounts[$sParentEmail], false);
|
||||
$oAccountToChange = $this->GetAccountFromCustomToken($aAccounts[$sParentEmail]);
|
||||
if ($oAccountToChange) {
|
||||
$this->SetAuthToken($oAccountToChange);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ trait UserAuth
|
|||
* @var string
|
||||
*/
|
||||
private $sSpecAuthToken = null;
|
||||
private $oSpecAuthAccount = null;
|
||||
|
||||
/**
|
||||
* Or use 'aes-256-xts' ?
|
||||
|
@ -142,33 +143,14 @@ trait UserAuth
|
|||
/**
|
||||
* @throws \RainLoop\Exceptions\ClientException
|
||||
*/
|
||||
public function GetAccountFromCustomToken(string $sToken, bool $bValidateShortToken = true, bool $bQ = false, bool $bThrowExceptionOnFalse = false): ?Account
|
||||
public function GetAccountFromCustomToken(string $sToken): ?Account
|
||||
{
|
||||
if (!empty($sToken)) {
|
||||
$aToken = $bQ ? Utils::DecodeKeyValuesQ($sToken) : Utils::DecodeKeyValues($sToken);
|
||||
return Account::NewInstanceFromTokenArray(
|
||||
return empty($sToken) ? null
|
||||
: Account::NewInstanceFromTokenArray(
|
||||
$this,
|
||||
$bQ ? Utils::DecodeKeyValuesQ($sToken) : Utils::DecodeKeyValues($sToken),
|
||||
$bThrowExceptionOnFalse
|
||||
Utils::DecodeKeyValues($sToken),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if ($bThrowExceptionOnFalse) {
|
||||
throw new ClientException(\RainLoop\Notifications::AuthError);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetShortLifeSpecAuthToken(int $iLife = 60): string
|
||||
{
|
||||
$aAccountHash = Utils::DecodeKeyValues($this->sSpecAuthToken);
|
||||
if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0]) {
|
||||
$aAccountHash[10] = \time() + $iLife;
|
||||
return Utils::EncodeKeyValues($aAccountHash);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,32 +158,56 @@ trait UserAuth
|
|||
*/
|
||||
public function getAccountFromToken(bool $bThrowExceptionOnFalse = true): ?Account
|
||||
{
|
||||
if (!\is_string($this->sSpecAuthToken)) {
|
||||
$this->sSpecAuthToken = '';
|
||||
if (isset($_COOKIE[self::AUTH_SPEC_LOGOUT_TOKEN_KEY])) {
|
||||
Utils::ClearCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY);
|
||||
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
|
||||
// Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
|
||||
} else {
|
||||
$sAuthAccountHash = Utils::GetCookie(self::AUTH_SPEC_TOKEN_KEY);
|
||||
if (empty($sAuthAccountHash)) {
|
||||
$oAccount = $this->GetAccountFromSignMeToken();
|
||||
if ($oAccount) {
|
||||
$this->SetAuthToken($oAccount);
|
||||
$sAuthAccountHash = $this->sSpecAuthToken;
|
||||
if (!$this->oSpecAuthAccount) {
|
||||
if (!\is_string($this->sSpecAuthToken)) {
|
||||
$this->sSpecAuthToken = '';
|
||||
if (isset($_COOKIE[self::AUTH_SPEC_LOGOUT_TOKEN_KEY])) {
|
||||
Utils::ClearCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY);
|
||||
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
|
||||
// Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
|
||||
} else {
|
||||
$sAuthAccountHash = Utils::GetCookie(self::AUTH_SPEC_TOKEN_KEY);
|
||||
if (empty($sAuthAccountHash)) {
|
||||
$oAccount = $this->GetAccountFromSignMeToken();
|
||||
if ($oAccount) {
|
||||
$this->SetAuthToken($oAccount);
|
||||
}
|
||||
} else {
|
||||
$this->sSpecAuthToken = $sAuthAccountHash;
|
||||
}
|
||||
}
|
||||
$this->sSpecAuthToken = $sAuthAccountHash ?: '';
|
||||
}
|
||||
|
||||
$aData = \json_decode(\MailSo\Base\Utils::UrlSafeBase64Decode($this->sSpecAuthToken), true);
|
||||
$aData = \is_array($aData) ? \SnappyMail\Crypt::Decrypt(\array_map('base64_decode', $aData)) : null;
|
||||
if (!empty($aData)) {
|
||||
$this->oSpecAuthAccount = Account::NewInstanceFromTokenArray(
|
||||
$this,
|
||||
$aData,
|
||||
$bThrowExceptionOnFalse
|
||||
);
|
||||
}
|
||||
|
||||
if ($bThrowExceptionOnFalse && !$this->oSpecAuthAccount) {
|
||||
throw new ClientException(\RainLoop\Notifications::AuthError);
|
||||
}
|
||||
}
|
||||
return $this->GetAccountFromCustomToken($this->sSpecAuthToken, true, true, $bThrowExceptionOnFalse);
|
||||
|
||||
return $this->oSpecAuthAccount;
|
||||
}
|
||||
|
||||
public function SetAuthToken(Account $oAccount): void
|
||||
{
|
||||
$sSpecAuthToken = $oAccount->GetAuthTokenQ();
|
||||
$sSpecAuthToken = \MailSo\Base\Utils::UrlSafeBase64Encode(\json_encode(\array_map(
|
||||
'base64_encode',
|
||||
\SnappyMail\Crypt::Encrypt(
|
||||
$oAccount,
|
||||
APP_SALT . Utils::GetShortToken()
|
||||
)
|
||||
)));
|
||||
|
||||
$this->sSpecAuthToken = $sSpecAuthToken;
|
||||
$this->oSpecAuthAccount = null;
|
||||
Utils::SetCookie(self::AUTH_SPEC_TOKEN_KEY, $sSpecAuthToken);
|
||||
|
||||
if (isset($aAccounts[$oAccount->Email()])) {
|
||||
|
|
|
@ -174,14 +174,6 @@ class Account implements \JsonSerializable
|
|||
return Utils::EncodeKeyValues($this->jsonSerialize());
|
||||
}
|
||||
|
||||
public function GetAuthTokenQ() : string
|
||||
{
|
||||
return Utils::EncodeKeyValuesQ($this->jsonSerialize());
|
||||
return \MailSo\Base\Utils::UrlSafeBase64Encode(
|
||||
\MailSo\Base\Crypt::Encrypt(\json_encode($this), \sha1(APP_SALT))
|
||||
);
|
||||
}
|
||||
|
||||
public static function NewInstanceByLogin(\RainLoop\Actions $oActions, string $sEmail, string $sLogin, string $sPassword, string $sClientCert = '', bool $bThrowException = false): ?self
|
||||
{
|
||||
$oAccount = null;
|
||||
|
|
|
@ -671,19 +671,19 @@ class ServiceActions
|
|||
$sSsoSubData = $this->Cacher()->Get(KeyPathHelper::SsoCacherKey($sSsoHash));
|
||||
if (!empty($sSsoSubData))
|
||||
{
|
||||
$mData = \array_map('base64_decode', \json_decode($sSsoSubData, true));
|
||||
$mData = \is_array($mData) ? \SnappyMail\Crypt::Decrypt($sSsoSubData, $sSsoHash) : null;
|
||||
$aData = \json_decode($sSsoSubData, true);
|
||||
$aData = \is_array($aData) ? \SnappyMail\Crypt::Decrypt(\array_map('base64_decode', $aData), $sSsoHash) : null;
|
||||
|
||||
$this->Cacher()->Delete(KeyPathHelper::SsoCacherKey($sSsoHash));
|
||||
|
||||
if (\is_array($mData) && !empty($mData['Email']) && isset($mData['Password'], $mData['Time']) &&
|
||||
(0 === $mData['Time'] || \time() - 10 < $mData['Time']))
|
||||
if (\is_array($aData) && !empty($aData['Email']) && isset($aData['Password'], $aData['Time']) &&
|
||||
(0 === $aData['Time'] || \time() - 10 < $aData['Time']))
|
||||
{
|
||||
$sEmail = \trim($mData['Email']);
|
||||
$sPassword = $mData['Password'];
|
||||
$sEmail = \trim($aData['Email']);
|
||||
$sPassword = $aData['Password'];
|
||||
|
||||
$aAdditionalOptions = isset($mData['AdditionalOptions']) && \is_array($mData['AdditionalOptions']) &&
|
||||
\count($mData['AdditionalOptions']) ? $mData['AdditionalOptions'] : null;
|
||||
$aAdditionalOptions = isset($aData['AdditionalOptions']) && \is_array($aData['AdditionalOptions']) &&
|
||||
\count($aData['AdditionalOptions']) ? $aData['AdditionalOptions'] : null;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -829,7 +829,7 @@ class ServiceActions
|
|||
$aAccounts = $this->oActions->GetAccounts($oAccount);
|
||||
if (isset($aAccounts[$sEmail]))
|
||||
{
|
||||
$oAccountToLogin = $this->oActions->GetAccountFromCustomToken($aAccounts[$sEmail], false);
|
||||
$oAccountToLogin = $this->oActions->GetAccountFromCustomToken($aAccounts[$sEmail]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,13 +30,20 @@ class Utils
|
|||
public static function EncodeKeyValues(array $aValues, string $sCustomKey = '') : string
|
||||
{
|
||||
return \MailSo\Base\Utils::UrlSafeBase64Encode(
|
||||
\MailSo\Base\Crypt::Encrypt(\json_encode($aValues), \md5(APP_SALT.$sCustomKey)));
|
||||
\MailSo\Base\Crypt::Encrypt(
|
||||
\json_encode($aValues),
|
||||
\md5(APP_SALT.$sCustomKey)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function DecodeKeyValues(string $sEncodedValues, string $sCustomKey = '') : array
|
||||
{
|
||||
return static::unserialize(
|
||||
\MailSo\Base\Crypt::Decrypt(\MailSo\Base\Utils::UrlSafeBase64Decode($sEncodedValues), \md5(APP_SALT.$sCustomKey))
|
||||
\MailSo\Base\Crypt::Decrypt(
|
||||
\MailSo\Base\Utils::UrlSafeBase64Decode($sEncodedValues),
|
||||
\md5(APP_SALT.$sCustomKey)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,9 +78,9 @@ abstract class Crypt
|
|||
public static function Decrypt(array $data, string $key = null) /* : mixed */
|
||||
{
|
||||
if (3 === \count($data) && isset($data[0], $data[1], $data[2])) {
|
||||
$fn = "\\SnappyMail\\Crypt::{$data[0]}Decrypt";
|
||||
if (\method_exists($fn)) {
|
||||
return $fn($data[2], $data[1], $key);
|
||||
$fn = "{$data[0]}Decrypt";
|
||||
if (\method_exists(__CLASS__, $fn)) {
|
||||
return \SnappyMail\Crypt::{$fn}($data[2], $data[1], $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,12 +106,12 @@ abstract class Crypt
|
|||
if (!\is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) {
|
||||
return null;
|
||||
}
|
||||
return \json_decode(\sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
return \json_decode(\zlib_decode(\sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
$data,
|
||||
APP_SALT,
|
||||
$nonce,
|
||||
static::Passphrase($key)
|
||||
));
|
||||
\str_pad('', \SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES, static::Passphrase($key))
|
||||
)));
|
||||
}
|
||||
|
||||
public static function SodiumEncrypt($data, string $nonce, string $key = null) : ?string
|
||||
|
@ -120,7 +120,7 @@ abstract class Crypt
|
|||
return null;
|
||||
}
|
||||
return \sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||
\json_encode($data),
|
||||
\zlib_encode(\json_encode($data), ZLIB_ENCODING_RAW, 9),
|
||||
APP_SALT,
|
||||
$nonce,
|
||||
\str_pad('', \SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES, static::Passphrase($key))
|
||||
|
@ -132,13 +132,13 @@ abstract class Crypt
|
|||
if (!$data || !$iv || !static::$cipher || !\is_callable('openssl_decrypt')) {
|
||||
return null;
|
||||
}
|
||||
return \json_decode(\openssl_decrypt(
|
||||
return \json_decode(\zlib_decode(\openssl_decrypt(
|
||||
$data,
|
||||
static::$cipher,
|
||||
static::Passphrase($key),
|
||||
OPENSSL_RAW_DATA,
|
||||
$iv
|
||||
), true);
|
||||
)), true);
|
||||
}
|
||||
|
||||
public static function OpenSSLEncrypt($data, string $iv, string $key = null) : ?string
|
||||
|
@ -147,7 +147,7 @@ abstract class Crypt
|
|||
return null;
|
||||
}
|
||||
return \openssl_encrypt(
|
||||
\json_encode($data),
|
||||
\zlib_encode(\json_encode($data), ZLIB_ENCODING_RAW, 9),
|
||||
static::$cipher,
|
||||
static::Passphrase($key),
|
||||
OPENSSL_RAW_DATA,
|
||||
|
@ -161,10 +161,10 @@ abstract class Crypt
|
|||
return null;
|
||||
}
|
||||
$key = $salt . static::Passphrase($key);
|
||||
return \json_decode(\is_callable('xxtea_decrypt')
|
||||
return \json_decode(\zlib_decode(\is_callable('xxtea_decrypt')
|
||||
? \xxtea_decrypt($data, $key)
|
||||
: \MailSo\Base\Xxtea::decrypt($data, $key)
|
||||
, true);
|
||||
), true);
|
||||
}
|
||||
|
||||
public static function XxteaEncrypt($data, string $salt, string $key = null) : ?string
|
||||
|
@ -172,7 +172,7 @@ abstract class Crypt
|
|||
if (!$data || !$salt) {
|
||||
return null;
|
||||
}
|
||||
$data = \json_encode($data);
|
||||
$data = \zlib_encode(\json_encode($data), ZLIB_ENCODING_RAW, 9);
|
||||
$key = $salt . static::Passphrase($key);
|
||||
return \is_callable('xxtea_encrypt')
|
||||
? \xxtea_encrypt($data, $key)
|
||||
|
|
Loading…
Reference in a new issue