From 5cc738e2ba925fa0cfb927c27b2cc8bbfe42e6f9 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 30 May 2022 13:12:01 +0200 Subject: [PATCH] Resolve #422 --- plugins/change-password-froxlor/driver.php | 107 +++++++++++++++++++++ plugins/change-password-froxlor/index.php | 20 ++++ 2 files changed, 127 insertions(+) create mode 100644 plugins/change-password-froxlor/driver.php create mode 100644 plugins/change-password-froxlor/index.php diff --git a/plugins/change-password-froxlor/driver.php b/plugins/change-password-froxlor/driver.php new file mode 100644 index 000000000..0e26d32c3 --- /dev/null +++ b/plugins/change-password-froxlor/driver.php @@ -0,0 +1,107 @@ +oConfig = $oConfig; + $this->oLogger = $oLogger; + } + + public static function isSupported() : bool + { + return \class_exists('PDO', false) + // The PHP extension PDO (mysql) must be installed to use this plugin + && \in_array('mysql', \PDO::getAvailableDrivers()); + } + + public static function configMapping() : array + { + return array( + \RainLoop\Plugins\Property::NewInstance('froxlor_dsn')->SetLabel('Froxlor PDO dsn') + ->SetDefaultValue('mysql:host=localhost;dbname=froxlor;charset=utf8'), + \RainLoop\Plugins\Property::NewInstance('froxlor_user')->SetLabel('User'), + \RainLoop\Plugins\Property::NewInstance('froxlor_password')->SetLabel('Password') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD), + \RainLoop\Plugins\Property::NewInstance('froxlor_allowed_emails')->SetLabel('Allowed emails') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT) + ->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net') + ->SetDefaultValue('*') + ); + } + + public function ChangePassword(\RainLoop\Model\Account $oAccount, string $sPrevPassword, string $sNewPassword) : bool + { + if (!\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->oConfig->Get('plugin', 'froxlor_allowed_emails', ''))) { + return false; + } + + try + { + if ($this->oLogger) { + $this->oLogger->Write('froxlor: Try to change password for '.$oAccount->Email()); + } + + $oPdo = new \PDO( + $this->oConfig->Get('plugin', 'froxlor_dsn', ''), + $this->oConfig->Get('plugin', 'froxlor_user', ''), + $this->oConfig->Get('plugin', 'froxlor_password', ''), + array( + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION + ) + ); + + $oStmt = $oPdo->prepare('SELECT password_enc, id FROM mail_users WHERE username = ? LIMIT 1'); + + if ($oStmt->execute(array($oAccount->IncLogin()))) { + $aFetchResult = $oStmt->fetch(\PDO::FETCH_ASSOC); + if (!empty($aFetchResult['id'])) { + $sDbPassword = $aFetchResult['password_enc']; + $sDbSalt = \substr($sDbPassword, 0, \strrpos($sDbPassword, '$')); + if (\crypt($sPrevPassword, $sDbSalt) === $sDbPassword) { + + $oStmt = $oPdo->prepare('UPDATE mail_users SET password_enc = ? WHERE id = ?'); + + return !!$oStmt->execute(array( + $this->cryptPassword($sNewPassword), + $aFetchResult['id'] + )); + } + } + } + } + catch (\Exception $oException) + { + if ($this->oLogger) { + $this->oLogger->WriteException($oException); + } + } + return false; + } + + private function cryptPassword(string $sPassword) : string + { + if (\defined('CRYPT_SHA512') && CRYPT_SHA512) { + $sSalt = '$6$rounds=5000$' . \bin2hex(\random_bytes(8)) . '$'; + } elseif (\defined('CRYPT_SHA256') && CRYPT_SHA256) { + $sSalt = '$5$rounds=5000$' . \bin2hex(\random_bytes(8)) . '$'; + } else { + $sSalt = '$1$' . \bin2hex(\random_bytes(6)) . '$'; + } + return \crypt($sPassword, $sSalt); + } +} diff --git a/plugins/change-password-froxlor/index.php b/plugins/change-password-froxlor/index.php new file mode 100644 index 000000000..9e0bbd160 --- /dev/null +++ b/plugins/change-password-froxlor/index.php @@ -0,0 +1,20 @@ +