Seditio Source
Root |
./othercms/PHPFusion 9.10.20/includes/classes/PHPFusion/PasswordAuth.php
<?php
/*-------------------------------------------------------+
| PHPFusion Content Management System
| Copyright (C) PHP Fusion Inc
| https://phpfusion.com/
+--------------------------------------------------------+
| Filename: PasswordAuth.php
| Author: Core Development Team
+--------------------------------------------------------+
| This program is released as free software under the
| Affero GPL license. You can redistribute it and/or
| modify it under the terms of this license which you
| can read by viewing the included agpl.txt or online
| at www.gnu.org/licenses/agpl.html. Removal of this
| copyright header is strictly prohibited without
| written permission from the original author(s).
+--------------------------------------------------------*/
namespace PHPFusion;
/**
 * Class PasswordAuth
 *
 * @package PHPFusion
 */
class PasswordAuth {
    public
$currentAlgo = "";
    public
$currentSalt = "";
    public
$currentPasswordHash = "";
    public
$inputPassword = "";
    public
$inputNewPassword = "";
    public
$inputNewPassword2 = "";
    public
$currentPassCheckLength = 8;
    public
$currentPassCheckCase = FALSE;
    public
$currentPassCheckNum = FALSE;
    public
$currentPassCheckSpecialchar = FALSE;
    private
$newAlgo;
    private
$newSalt;
    private
$newPasswordHash;
    private
$error = '';

   
/**
     * PasswordAuth constructor.
     *
     * @param string $passwordAlgorithm
     */
   
public function __construct($passwordAlgorithm = 'sha256') {
       
$this->newAlgo = $passwordAlgorithm;
    }

   
/**
     * Checks if new password is valid
     *
     * @param bool $createNewHash
     *
     * @return bool
     */
   
public function isValidCurrentPassword($createNewHash = FALSE) {
       
$inputPasswordHash = $this->hashPassword($this->inputPassword, $this->currentAlgo, $this->currentSalt);
        if (
$inputPasswordHash == $this->currentPasswordHash) {
            if (
$createNewHash === TRUE) {
               
$this->setNewHash($this->inputPassword);
            }

            return
TRUE;
        } else {
            return
FALSE;
        }
    }

   
/**
     * Strengh settings check
     *
     * @param string $value
     *
     * @return bool
     */
   
public function checkInputPassword($value) {
       
$locale = fusion_get_locale();

        if (
$value) {
           
//$currentPassCheckLength
           
$regex = self::passwordStrengthOpts($this->currentPassCheckLength, FALSE);
            if (!
preg_match('/'.$regex.'/', $value)) {
               
$this->error = $locale['u303'];
                return
FALSE;
            }

            if (
$this->currentPassCheckNum) {
               
// Check contains number
               
$regex = self::passwordStrengthOpts($this->currentPassCheckLength, $this->currentPassCheckNum);
                if (!
preg_match('/'.$regex.'/', $value)) {
                   
$this->error = $locale['u302'];
                    return
FALSE;
                }
            }

            if (
$this->currentPassCheckCase) {
               
// Check contains at least 1 upper and 1 lowercase
               
$regex = self::passwordStrengthOpts($this->currentPassCheckLength, $this->currentPassCheckNum, $this->currentPassCheckCase);
                if (!
preg_match('/'.$regex.'/', $value)) {
                   
$this->error = $locale['u301'];
                    return
FALSE;
                }
            }

            if (
$this->currentPassCheckSpecialchar) {
               
// Must contain at least 1 special char
               
$regex = self::passwordStrengthOpts($this->currentPassCheckLength, $this->currentPassCheckNum, $this->currentPassCheckCase, $this->currentPassCheckSpecialchar);

                if (!
preg_match('/'.$regex.'/', $value)) {
                   
$this->error = $locale['u300'];
                    return
FALSE;
                }
            }
        }

        return
TRUE;
    }

   
/**
     * @param int   $minimum_length
     * @param bool  $number
     * @param false $camelcase
     * @param false $special_char
     *
     * @return string
     */
   
public static function passwordStrengthOpts($minimum_length = 8, $number = TRUE, $camelcase = FALSE, $special_char = FALSE) {
       
$pass_regex = '(?=.*?[A-Za-z])';
        if (
$camelcase) {
           
$pass_regex = '(?=.*?[a-z])(?=.*[A-Z])';
        }

        if (
$number) {
           
$pass_regex .= '(?=.*?[0-9])';
        }

        if (
$special_char) {
           
$pass_regex .= '(?=.*?[@!#$%&\[\]()=\-_\\\\\/?+*.,;^*])';
        }

        return
'^'.$pass_regex.'.{'.$minimum_length.',64}$';
    }

   
/**
     * Encrypts the password with given algorithm and salt
     *
     * @param string $password
     * @param string $algorithm
     * @param string $salt
     *
     * @return string
     */
   
private function hashPassword($password, $algorithm, $salt) {
        if (
$algorithm != "md5") {
            return
hash_hmac($algorithm, $password, $salt);
        } else {
            return
md5(md5($password));
        }
    }

   
/**
     *Generate new password hash and password salt
     *
     * @param $password
     */
   
protected function setNewHash($password) {
       
$this->newSalt = self::getNewRandomSalt();
       
$this->newPasswordHash = $this->hashPassword($password, $this->newAlgo, $this->newSalt);
    }

   
/**
     * Generate a random password salt
     *
     * @param int $length
     *
     * @return string
     */
   
public static function getNewRandomSalt($length = 12) {
        return
sha1(self::getNewPassword($length));
    }

   
/**
     * Generates a random password with given length
     *
     * @param int $length
     *
     * @return string
     */
   
public static function getNewPassword($length = 12) {
       
$chars = ["abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ", "123456789", "@!#$%&/()=-_?+*.,:;"];
       
$count = [(strlen($chars[0]) - 1), (strlen($chars[1]) - 1), (strlen($chars[2]) - 1)];
        if (
$length > 64) {
           
$length = 64;
        }
       
$pass = "";
        for (
$i = 0; $i <= $length; $i++) {
           
$type = mt_rand(0, 2);
           
$pass .= substr($chars[$type], mt_rand(0, $count[$type]), 1);
        }

        return
$pass;
    }


    public function
getError() {
        return
$this->error;
    }

   
/**
     * Get hash, salt, and algo
     *
     * @param $user_password
     *
     * @return array
     */
   
public function setNewPassword($user_password) {
       
$salt = self::getNewRandomSalt();

        return [
           
"salt" => $salt,
           
"algo" => $this->newAlgo,
           
"hash" => $this->hashPassword($user_password, $this->newAlgo, $salt)
        ];
    }

   
/**
     * Checks whether new input password is valid
     *
     * @return int
     */
   
public function isValidNewPassword() {
        if (
$this->inputNewPassword != $this->inputPassword) {
            if (
$this->inputNewPassword == $this->inputNewPassword2) {
                if (
$this->isValidPasswordInput()) {
                   
$this->setNewHash($this->inputNewPassword);

                    return
0;
                } else {
                   
// New password contains invalid chars
                   
return 3;
                }
            } else {
               
// The two new passwords are not identical
               
return 2;
            }
        } else {
           
// New password can not be equal you current password
           
return 1;
        }
    }

   
/**
     * Checks if new password input is valid
     *
     * @return bool
     */
   
private function isValidPasswordInput() {
        if (
preg_match("/^[0-9A-Z@<>\[\]!#$%&\/\(\)=\-_?+\*\.,:~;\{\}]{8,64}$/i", $this->inputNewPassword)) {
            return
TRUE;
        } else {
            return
FALSE;
        }
    }

   
/**
     * Get new password algorithem
     *
     * @return string
     */
   
public function getNewAlgo() {
        return
$this->newAlgo;
    }

   
/**
     * Get new password salt
     *
     * @return mixed
     */
   
public function getNewSalt() {
        return
$this->newSalt;
    }

   
/**
     * Get new password hash
     *
     * @return mixed
     */
   
public function getNewHash() {
        return
$this->newPasswordHash;
    }
}