-
-
Save daigo75/5141929 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @copyright Vanilla Forums Inc. | |
* @license GNU GPL2 | |
*/ | |
/** | |
* Instantiating this class will store current user's ID from cookie as $this->UserID. | |
* | |
* Usage | |
* $VanillaIdentity = new VanillaIdentity(); | |
* $LoggedUserID = $VanillaIdentity->GetLoggerUserID(); | |
* | |
* Please read class documentation to see what options can be passed to its | |
* constructor. | |
* | |
* @see VanillaIdentity::__construct() | |
*/ | |
class VanillaIdentity { | |
# Copy these from Vanilla config | |
// @var string The name of the cookie used by Vanilla | |
private $CookieName; | |
// @var string The salt used to hash the cookie | |
private $CookieSalt; | |
// @var string The hash method used to hash the cookie | |
private $CookieHashMethod; | |
// @var int The User ID retrieved from the cookies | |
public $UserID = 0; | |
// @var array Contains a list of the hash methods supported by the class | |
protected $ValidHashMethods = array( | |
'md5', | |
'sha1', | |
); | |
// @var int User ID that indicates "No User" | |
const NO_USER_ID = 0; | |
const DEFAULT_COOKIE_NAME = 'Vanilla'; | |
const DEFAULT_COOKIE_SALT = ''; | |
const DEFAULT_COOKIE_HASH_METHOD = 'md5'; | |
/** | |
* Class constructor. | |
* | |
* @param string CookieName The name of the cookie used by Vanilla. | |
* @param string CookieSalt The salt used to hash the cookie. | |
* @param string $HashMethod The hashing method to use on $Data. Options are MD5 or SHA1. | |
*/ | |
public function __construct($CookieName = self::DEFAULT_COOKIE_NAME, $CookieSalt = self::DEFAULT_COOKIE_SALT, | |
$CookieHashMethod = self::DEFAULT_COOKIE_HASH_METHOD) { | |
$CookieHashMethod = strtolower($CookieHashMethod); | |
if(!InArrayI($CookieHashMethod, $this->ValidHashMethods)) { | |
throw new InvalidArgumentException(sprintf('Invalid hash method: "%s". Valid methods are %s.'), | |
$CookieHashMethod, | |
implode(', ', $this->ValidHashMethods)); | |
} | |
$this->CookieName = $CookieName; | |
$this->CookieSalt = $CookieSalt; | |
$this->CookieHashMethod = $CookieHashMethod; | |
} | |
/** | |
* Returns the unique id assigned to the user in the database (retrieved | |
* from the session cookie if the cookie authenticates) or FALSE if not | |
* found or authentication fails. | |
* | |
* @return int The ID of the User currently logged on Vanilla Forums, or zero | |
* if he is not logged in. | |
*/ | |
public function GetLoggedUserID() { | |
if (!$this->_CheckCookie($this->CookieName)) { | |
return self::NO_USER_ID; | |
} | |
list($UserID, $Expiration) = $this->GetCookiePayload($this->CookieName); | |
// TODO Replace magic number "-2" with constant explaining what it means | |
// allow for handshake special id | |
if (!is_numeric($UserID) || $UserID < -2) { | |
$this->UserID = self::NO_USER_ID; | |
} | |
else{ | |
$this->UserID = $UserID; | |
} | |
return $this->UserID; | |
} | |
protected function GetCookiePayload($CookieName) { | |
if (!$this->CheckCookie($CookieName)) { | |
return FALSE; | |
} | |
$Payload = explode('|', $_COOKIE[$CookieName]); | |
// Get rid of check fields like HashKey, HMAC and Time | |
array_shift($Payload); | |
array_shift($Payload); | |
array_shift($Payload); | |
return $Payload; | |
} | |
protected function _CheckCookie($CookieName) { | |
return $this->CheckCookie($CookieName); | |
} | |
protected function CheckCookie($CookieName) { | |
if (empty($_COOKIE[$CookieName])) { | |
return FALSE; | |
} | |
$CookieHashMethod = $this->CookieHashMethod; | |
$CookieSalt = $this->CookieSalt; | |
$CookieData = explode('|', $_COOKIE[$CookieName]); | |
if (count($CookieData) < 5) { | |
return FALSE; | |
} | |
list($HashKey, $CookieHash, $Time, $UserID, $Expiration) = $CookieData; | |
if ($Expiration < time() && $Expiration != 0) { | |
return FALSE; | |
} | |
$Key = self::_Hash($HashKey, $CookieHashMethod, $CookieSalt); | |
// VanillaIdentity::_Hash() just calls VanillaIdentity::__HashHMAC(). Why | |
// not just using the latter? | |
$GeneratedHash = self::_HashHMAC($CookieHashMethod, $HashKey, $Key); | |
if ($CookieHash != $GeneratedHash) { | |
return FALSE; | |
} | |
return TRUE; | |
} | |
/** | |
* Returns $this->_HashHMAC with the provided data, the default hashing method | |
* (md5), and the server's COOKIE.SALT string as the key. | |
* | |
* @param string $Data The data to place in the hash. | |
* @param string $CookieHashMethod The hashing method to use on $Data. Options are MD5 or SHA1. | |
* @param string $CookieSalt The salt to use when hashing the data. | |
* @return string The hash of the data. | |
* | |
*/ | |
protected static function _Hash($Data, $CookieHashMethod, $CookieSalt) { | |
return self::_HashHMAC($CookieHashMethod, $Data, $CookieSalt); | |
} | |
/** | |
* Returns the provided data hashed with the specified method using the | |
* specified key. | |
* | |
* @param string $HashMethod The hashing method to use on $Data. Options are MD5 or SHA1. | |
* @param string $Data The data to place in the hash. | |
* @param string $Key The key to use when hashing the data. | |
* @return string The hash of the data. | |
*/ | |
protected static function _HashHMAC($HashMethod, $Data, $Key) { | |
$PackFormats = array('md5' => 'H32', 'sha1' => 'H40'); | |
if (!isset($PackFormats[$HashMethod])) { | |
return false; | |
} | |
$PackFormat = $PackFormats[$HashMethod]; | |
// this is the equivalent of "strlen($Key) > 64": | |
if (isset($Key[63])) { | |
$Key = pack($PackFormat, $HashMethod($Key)); | |
} | |
else { | |
$Key = str_pad($Key, 64, chr(0)); | |
} | |
$InnerPad = (substr($Key, 0, 64) ^ str_repeat(chr(0x36), 64)); | |
$OuterPad = (substr($Key, 0, 64) ^ str_repeat(chr(0x5C), 64)); | |
return $HashMethod($OuterPad . pack($PackFormat, $HashMethod($InnerPad . $Data))); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment