From 6d88a939756fea185e6b8d182bd1b9fdc51c084f Mon Sep 17 00:00:00 2001 From: kromonos Date: Tue, 19 Dec 2017 00:11:13 +0100 Subject: [PATCH] Add files via upload --- .../FroxlorChangePasswordDriver.php | 293 ++++++++++++++++++ plugins/froxlor-change-password/LICENSE | 20 ++ plugins/froxlor-change-password/README | 1 + plugins/froxlor-change-password/VERSION | 1 + plugins/froxlor-change-password/index.php | 76 +++++ 5 files changed, 391 insertions(+) create mode 100644 plugins/froxlor-change-password/FroxlorChangePasswordDriver.php create mode 100644 plugins/froxlor-change-password/LICENSE create mode 100644 plugins/froxlor-change-password/README create mode 100644 plugins/froxlor-change-password/VERSION create mode 100644 plugins/froxlor-change-password/index.php diff --git a/plugins/froxlor-change-password/FroxlorChangePasswordDriver.php b/plugins/froxlor-change-password/FroxlorChangePasswordDriver.php new file mode 100644 index 000000000..6ee9cd553 --- /dev/null +++ b/plugins/froxlor-change-password/FroxlorChangePasswordDriver.php @@ -0,0 +1,293 @@ +sDsn = $sDsn; + $this->sUser = $sUser; + $this->sPassword = $sPassword; + + return $this; + } + + /** + * @param string $sAllowedEmails + * + * @return \FroxlorChangePasswordDriver + */ + public function SetAllowedEmails($sAllowedEmails) + { + $this->sAllowedEmails = $sAllowedEmails; + return $this; + } + + /** + * @param \MailSo\Log\Logger $oLogger + * + * @return \FroxlorChangePasswordDriver + */ + public function SetLogger($oLogger) + { + if ($oLogger instanceof \MailSo\Log\Logger) + { + $this->oLogger = $oLogger; + } + + return $this; + } + + /** + * @param \RainLoop\Account $oAccount + * + * @return bool + */ + public function PasswordChangePossibility($oAccount) + { + return $oAccount && $oAccount->Email() && + \RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails); + } + + /** + * @param \RainLoop\Account $oAccount + * @param string $sPrevPassword + * @param string $sNewPassword + * + * @return bool + */ + public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword) + { + if ($this->oLogger) { + $this->oLogger->Write('Froxlor: Try to change password for '.$oAccount->Email()); + } + + $bResult = false; + if (!empty($this->sDsn) && 0 < \strlen($this->sUser) && 0 < \strlen($this->sPassword) && $oAccount) + { + try + { + $oPdo = new \PDO($this->sDsn, $this->sUser, $this->sPassword); + $oPdo->setAttribute(\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->fetchAll(\PDO::FETCH_ASSOC); + if (\is_array($aFetchResult) && isset($aFetchResult[0]['password_enc'], $aFetchResult[0]['id'])) + { + $sDbPassword = \stripslashes($aFetchResult[0]['password_enc']); + + if ( $this->validatePasswordLogin( $sDbPassword, $sPrevPassword ) ) { + $sEncNewPassword = $this->cryptPassword($sNewPassword, 3); + $oStmt = $oPdo->prepare('UPDATE mail_users SET password_enc = ?,password = ? WHERE id = ?'); + $bResult = (bool) $oStmt->execute( + array($sEncNewPassword, $sNewPassword, $aFetchResult[0]['id'])); + } + } + } + } + catch (\Exception $oException) + { + if ($this->oLogger) + { + $this->oLogger->WriteException($oException); + } + } + } + + return $bResult; + } + + /** + * @param string $sPassword + * @return string + */ + private function cryptPassword($sPassword, $type = 3) + { + return $this->makeCryptPassword($sPassword,$type); + } + + /** + * This file is part of the Froxlor project. + * Copyright (c) 2010 the Froxlor Team (see authors). + * + * For the full copyright and license information, please view the COPYING + * file that was distributed with this source code. You can also view the + * COPYING file online at http://files.froxlor.org/misc/COPYING.txt + * + * @copyright (c) the authors + * @author Michal Wojcik + * @author Michael Kaufmann + * @author Froxlor team (2010-) + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Functions + * + */ + + /** + * Make crypted password from clear text password + * + * @author Michal Wojcik + * @author Michael Kaufmann + * @author Froxlor team (2010-) + * + * 0 - default crypt (depenend on system configuration) + * 1 - MD5 $1$ + * 2 - BLOWFISH $2a$ | $2y$07$ (on php 5.3.7+) + * 3 - SHA-256 $5$ (default) + * 4 - SHA-512 $6$ + * + * @param string $password Password to be crypted + * + * @return string encrypted password + */ + private function makeCryptPassword ($password,$type = 3) { + switch ($type) { + case 0: + $cryptPassword = \crypt($password); + break; + case 1: + $cryptPassword = \crypt($password, '$1$' . $this->generatePassword(true). $this->generatePassword(true)); + break; + case 2: + if (\version_compare(\phpversion(), '5.3.7', '<')) { + $cryptPassword = \crypt($password, '$2a$' . $this->generatePassword(true). $this->generatePassword(true)); + } else { + // Blowfish hashing with a salt as follows: "$2a$", "$2x$" or "$2y$", + // a two digit cost parameter, "$", and 22 characters from the alphabet "./0-9A-Za-z" + $cryptPassword = \crypt( + $password, + '$2y$07$' . \substr($this->generatePassword(true).$this->generatePassword(true).$this->generatePassword(true), 0, 22) + ); + } + break; + case 3: + $cryptPassword = \crypt($password, '$5$' . $this->generatePassword(true). $this->generatePassword(true)); + break; + case 4: + $cryptPassword = \crypt($password, '$6$' . $this->generatePassword(true). $this->generatePassword(true)); + break; + default: + $cryptPassword = \crypt($password); + break; + } + + return $cryptPassword; + } + + /** + * Generates a random password + * + * @param boolean $isSalt + * optional, create a hash for a salt used in makeCryptPassword because crypt() does not like some special characters in its salts, default is false + */ + private function generatePassword($isSalt = false) + { + $alpha_lower = 'abcdefghijklmnopqrstuvwxyz'; + $alpha_upper = \strtoupper($alpha_lower); + $numeric = '0123456789'; + $special = '!?<>ยง$%&+#='; + $length = 10; + + $pw = $this->special_shuffle($alpha_lower); + $n = \floor(($length) / 4); + $pw .= \mb_substr($this->special_shuffle($alpha_upper), 0, $n); + $pw .= \mb_substr($this->special_shuffle($numeric), 0, $n); + $pw = \mb_substr($pw, - $length); + return $this->special_shuffle($pw); + } + + /** + * multibyte-character safe shuffle function + * + * @param string $str + * + * @return string + */ + private function special_shuffle($str = null) + { + $len = \mb_strlen($str); + $sploded = array(); + while ($len -- > 0) { + $sploded[] = \mb_substr($str, $len, 1); + } + \shuffle($sploded); + return \join('', $sploded); + } + + /** + * Function validatePasswordLogin + * + * compare user password-hash with given user-password + * and check if they are the same + * additionally it updates the hash if the system settings changed + * or if the very old md5() sum is used + * + * @param array $userinfo user-data from table + * @param string $password the password to validate + * @param string $table either panel_customers or panel_admins + * @param string $uid user-id-field in $table + * + * @return boolean + */ + private function validatePasswordLogin($pwd_hash, $password = null) { + + $systype = 3; // SHA256 + $update_hash = false; + // check for good'ole md5 + if (\strlen($pwd_hash) == 32 && \ctype_xdigit($pwd_hash)) { + $pwd_check = \md5($password); + $update_hash = true; + } else { + // cut out the salt from the hash + $pwd_salt = \str_replace(\substr(\strrchr($pwd_hash, "$"), 1), "", $pwd_hash); + // create same hash to compare + $pwd_check = \crypt($password, $pwd_salt); + // check whether the hash needs to be updated + $hash_type_chk = \substr($pwd_hash, 0, 3); + if (($systype == 1 && $hash_type_chk != '$1$') || // MD5 + ($systype == 2 && $hash_type_chk != '$2$') || // BLOWFISH + ($systype == 3 && $hash_type_chk != '$5$') || // SHA256 + ($systype == 4 && $hash_type_chk != '$6$') // SHA512 + ) { + $update_hash = true; + } + } + + return $pwd_check; + } + + +} diff --git a/plugins/froxlor-change-password/LICENSE b/plugins/froxlor-change-password/LICENSE new file mode 100644 index 000000000..10a788ceb --- /dev/null +++ b/plugins/froxlor-change-password/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bob Kromonos Achten + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/froxlor-change-password/README b/plugins/froxlor-change-password/README new file mode 100644 index 000000000..b3a26fa46 --- /dev/null +++ b/plugins/froxlor-change-password/README @@ -0,0 +1 @@ +Plugin that adds functionality to change the email account password (Froxlor). diff --git a/plugins/froxlor-change-password/VERSION b/plugins/froxlor-change-password/VERSION new file mode 100644 index 000000000..d3827e75a --- /dev/null +++ b/plugins/froxlor-change-password/VERSION @@ -0,0 +1 @@ +1.0 diff --git a/plugins/froxlor-change-password/index.php b/plugins/froxlor-change-password/index.php new file mode 100644 index 000000000..ae63855d5 --- /dev/null +++ b/plugins/froxlor-change-password/index.php @@ -0,0 +1,76 @@ +addHook('main.fabrica', 'MainFabrica'); + } + + /** + * @return string + */ + public function Supported() + { + if (!extension_loaded('pdo') || !class_exists('PDO')) + { + return 'The PHP exention PDO (mysql) must be installed to use this plugin'; + } + + $aDrivers = \PDO::getAvailableDrivers(); + if (!is_array($aDrivers) || !in_array('mysql', $aDrivers)) + { + return 'The PHP exention PDO (mysql) must be installed to use this plugin'; + } + + return ''; + } + + /** + * @param string $sName + * @param mixed $oProvider + */ + public function MainFabrica($sName, &$oProvider) + { + switch ($sName) + { + case 'change-password': + + $sDsn = \trim($this->Config()->Get('plugin', 'pdo_dsn', '')); + $sUser = (string) $this->Config()->Get('plugin', 'user', ''); + $sPassword = (string) $this->Config()->Get('plugin', 'password', ''); + + if (!empty($sDsn) && 0 < \strlen($sUser) && 0 < \strlen($sPassword)) + { + include_once __DIR__.'/FroxlorChangePasswordDriver.php'; + + $oProvider = new FroxlorChangePasswordDriver(); + $oProvider->SetLogger($this->Manager()->Actions()->Logger()); + $oProvider->SetConfig($sDsn, $sUser, $sPassword); + $oProvider->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', '')))); + } + + break; + } + } + + /** + * @return array + */ + public function configMapping() + { + return array( + \RainLoop\Plugins\Property::NewInstance('pdo_dsn')->SetLabel('Froxlor PDO dsn') + ->SetDefaultValue('mysql:host=127.0.0.1;dbname=froxlor'), + \RainLoop\Plugins\Property::NewInstance('user')->SetLabel('DB User') + ->SetDefaultValue('root'), + \RainLoop\Plugins\Property::NewInstance('password')->SetLabel('DB Password') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD) + ->SetDefaultValue(''), + \RainLoop\Plugins\Property::NewInstance('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('*') + ); + } +}