From: Andrew Dolgov Date: Wed, 20 Jun 2018 15:27:34 +0000 (+0300) Subject: move OTPHP to vendor/; additionally move Base32 class to OTPHP namespace X-Git-Tag: 18.8~18 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=310c18e6bbd8e7f78a0a45f0501cb1dc6fab2159;p=tt-rss.git move OTPHP to vendor/; additionally move Base32 class to OTPHP namespace --- diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php index f56048b2..da62ea70 100644 --- a/classes/pref/prefs.php +++ b/classes/pref/prefs.php @@ -147,7 +147,7 @@ class Pref_Prefs extends Handler_Protected { $_SESSION["prefs_op_result"] = "reset-to-defaults"; $sth = $this->pdo->prepare("DELETE FROM ttrss_user_prefs - WHERE (profile = :profile OR (:profile IS NULL AND profile IS NULL)) + WHERE (profile = :profile OR (:profile IS NULL AND profile IS NULL)) AND owner_uid = :uid"); $sth->execute([":profile" => $_SESSION['profile'], ":uid" => $_SESSION['uid']]); @@ -848,9 +848,6 @@ class Pref_Prefs extends Handler_Protected { } function otpqrcode() { - require_once "lib/otphp/vendor/base32.php"; - require_once "lib/otphp/lib/otp.php"; - require_once "lib/otphp/lib/totp.php"; require_once "lib/phpqrcode/phpqrcode.php"; $sth = $this->pdo->prepare("SELECT login,salt,otp_enabled @@ -860,7 +857,7 @@ class Pref_Prefs extends Handler_Protected { if ($row = $sth->fetch()) { - $base32 = new Base32(); + $base32 = new \OTPHP\Base32(); $login = $row["login"]; $otp_enabled = sql_bool_to_bool($row["otp_enabled"]); @@ -876,9 +873,6 @@ class Pref_Prefs extends Handler_Protected { } function otpenable() { - require_once "lib/otphp/vendor/base32.php"; - require_once "lib/otphp/lib/otp.php"; - require_once "lib/otphp/lib/totp.php"; $password = clean($_REQUEST["password"]); $otp = clean($_REQUEST["otp"]); @@ -894,7 +888,7 @@ class Pref_Prefs extends Handler_Protected { if ($row = $sth->fetch()) { - $base32 = new Base32(); + $base32 = new \OTPHP\Base32(); $secret = $base32->encode(sha1($row["salt"])); $topt = new \OTPHP\TOTP($secret); @@ -902,7 +896,7 @@ class Pref_Prefs extends Handler_Protected { $otp_check = $topt->now(); if ($otp == $otp_check) { - $sth = $this->pdo->prepare("UPDATE ttrss_users + $sth = $this->pdo->prepare("UPDATE ttrss_users SET otp_enabled = true WHERE id = ?"); $sth->execute([$_SESSION['uid']]); diff --git a/lib/otphp/LICENCE b/lib/otphp/LICENCE deleted file mode 100644 index d14cbc23..00000000 --- a/lib/otphp/LICENCE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2011 Le Lag - -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/lib/otphp/lib/hotp.php b/lib/otphp/lib/hotp.php deleted file mode 100644 index 7092fd9f..00000000 --- a/lib/otphp/lib/hotp.php +++ /dev/null @@ -1,74 +0,0 @@ -generateOTP($count); - } - - - /** - * Verify if a password is valid for a specific counter value - * - * @param integer $otp the one-time password - * @param integer $counter the counter value - * @return bool true if the counter is valid, false otherwise - */ - public function verify($otp, $counter) { - return ($otp == $this->at($counter)); - } - - /** - * Returns the uri for a specific secret for hotp method. - * Can be encoded as a image for simple configuration in - * Google Authenticator. - * - * @param string $name the name of the account / profile - * @param integer $initial_count the initial counter - * @return string the uri for the hmac secret - */ - public function provisioning_uri($name, $initial_count) { - return "otpauth://hotp/".urlencode($name)."?secret={$this->secret}&counter=$initial_count"; - } - } - -} diff --git a/lib/otphp/lib/otp.php b/lib/otphp/lib/otp.php deleted file mode 100644 index 77bcfe97..00000000 --- a/lib/otphp/lib/otp.php +++ /dev/null @@ -1,120 +0,0 @@ -digits = isset($opt['digits']) ? $opt['digits'] : 6; - $this->digest = isset($opt['digest']) ? $opt['digest'] : 'sha1'; - $this->secret = $secret; - } - - /** - * Generate a one-time password - * - * @param integer $input : number used to seed the hmac hash function. - * This number is usually a counter (HOTP) or calculated based on the current - * timestamp (see TOTP class). - * @return integer the one-time password - */ - public function generateOTP($input) { - $hash = hash_hmac($this->digest, $this->intToBytestring($input), $this->byteSecret()); - foreach(str_split($hash, 2) as $hex) { // stupid PHP has bin2hex but no hex2bin WTF - $hmac[] = hexdec($hex); - } - $offset = $hmac[19] & 0xf; - $code = ($hmac[$offset+0] & 0x7F) << 24 | - ($hmac[$offset + 1] & 0xFF) << 16 | - ($hmac[$offset + 2] & 0xFF) << 8 | - ($hmac[$offset + 3] & 0xFF); - return $code % pow(10, $this->digits); - } - - /** - * Returns the binary value of the base32 encoded secret - * @access private - * This method should be private but was left public for - * phpunit tests to work. - * @return binary secret key - */ - public function byteSecret() { - return \Base32::decode($this->secret); - } - - /** - * Turns an integer in a OATH bytestring - * @param integer $int - * @access private - * @return string bytestring - */ - public function intToBytestring($int) { - $result = Array(); - while($int != 0) { - $result[] = chr($int & 0xFF); - $int >>= 8; - } - return str_pad(join(array_reverse($result)), 8, "\000", STR_PAD_LEFT); - } - } -} diff --git a/lib/otphp/lib/otphp.php b/lib/otphp/lib/otphp.php deleted file mode 100644 index a6c6f8d6..00000000 --- a/lib/otphp/lib/otphp.php +++ /dev/null @@ -1,27 +0,0 @@ -interval = isset($opt['interval']) ? $opt['interval'] : 30; - parent::__construct($s, $opt); - } - - /** - * Get the password for a specific timestamp value - * - * @param integer $timestamp the timestamp which is timecoded and - * used to seed the hmac hash function. - * @return integer the One Time Password - */ - public function at($timestamp) { - return $this->generateOTP($this->timecode($timestamp)); - } - - /** - * Get the password for the current timestamp value - * - * @return integer the current One Time Password - */ - public function now() { - return $this->generateOTP($this->timecode(time())); - } - - /** - * Verify if a password is valid for a specific counter value - * - * @param integer $otp the one-time password - * @param integer $timestamp the timestamp for the a given time, defaults to current time. - * @return bool true if the counter is valid, false otherwise - */ - public function verify($otp, $timestamp = null) { - if($timestamp === null) - $timestamp = time(); - return ($otp == $this->at($timestamp)); - } - - /** - * Returns the uri for a specific secret for totp method. - * Can be encoded as a image for simple configuration in - * Google Authenticator. - * - * @param string $name the name of the account / profile - * @return string the uri for the hmac secret - */ - public function provisioning_uri($name) { - return "otpauth://totp/".urlencode($name)."?secret={$this->secret}"; - } - - /** - * Transform a timestamp in a counter based on specified internal - * - * @param integer $timestamp - * @return integer the timecode - */ - protected function timecode($timestamp) { - return (int)( (((int)$timestamp * 1000) / ($this->interval * 1000))); - } - } - -} diff --git a/lib/otphp/vendor/base32.php b/lib/otphp/vendor/base32.php deleted file mode 100644 index 99c3f1bf..00000000 --- a/lib/otphp/vendor/base32.php +++ /dev/null @@ -1,83 +0,0 @@ -'0', 'B'=>'1', 'C'=>'2', 'D'=>'3', 'E'=>'4', 'F'=>'5', 'G'=>'6', 'H'=>'7', - 'I'=>'8', 'J'=>'9', 'K'=>'10', 'L'=>'11', 'M'=>'12', 'N'=>'13', 'O'=>'14', 'P'=>'15', - 'Q'=>'16', 'R'=>'17', 'S'=>'18', 'T'=>'19', 'U'=>'20', 'V'=>'21', 'W'=>'22', 'X'=>'23', - 'Y'=>'24', 'Z'=>'25', '2'=>'26', '3'=>'27', '4'=>'28', '5'=>'29', '6'=>'30', '7'=>'31' - ); - - /** - * Use padding false when encoding for urls - * - * @return base32 encoded string - * @author Bryan Ruiz - **/ - public static function encode($input, $padding = true) { - if(empty($input)) return ""; - $input = str_split($input); - $binaryString = ""; - for($i = 0; $i < count($input); $i++) { - $binaryString .= str_pad(base_convert(ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT); - } - $fiveBitBinaryArray = str_split($binaryString, 5); - $base32 = ""; - $i=0; - while($i < count($fiveBitBinaryArray)) { - $base32 .= self::$map[base_convert(str_pad($fiveBitBinaryArray[$i], 5,'0'), 2, 10)]; - $i++; - } - if($padding && ($x = strlen($binaryString) % 40) != 0) { - if($x == 8) $base32 .= str_repeat(self::$map[32], 6); - else if($x == 16) $base32 .= str_repeat(self::$map[32], 4); - else if($x == 24) $base32 .= str_repeat(self::$map[32], 3); - else if($x == 32) $base32 .= self::$map[32]; - } - return $base32; - } - - public static function decode($input) { - if(empty($input)) return; - $paddingCharCount = substr_count($input, self::$map[32]); - $allowedValues = array(6,4,3,1,0); - if(!in_array($paddingCharCount, $allowedValues)) return false; - for($i=0; $i<4; $i++){ - if($paddingCharCount == $allowedValues[$i] && - substr($input, -($allowedValues[$i])) != str_repeat(self::$map[32], $allowedValues[$i])) return false; - } - $input = str_replace('=','', $input); - $input = str_split($input); - $binaryString = ""; - for($i=0; $i < count($input); $i = $i+8) { - $x = ""; - if(!in_array($input[$i], self::$map)) return false; - for($j=0; $j < 8; $j++) { - $x .= str_pad(base_convert(@self::$flippedMap[@$input[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT); - } - $eightBits = str_split($x, 8); - for($z = 0; $z < count($eightBits); $z++) { - $binaryString .= ( ($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48 ) ? $y:""; - } - } - return $binaryString; - } -} - diff --git a/lib/otphp/vendor/libs.php b/lib/otphp/vendor/libs.php deleted file mode 100644 index 742c7b98..00000000 --- a/lib/otphp/vendor/libs.php +++ /dev/null @@ -1,26 +0,0 @@ -'0', 'B'=>'1', 'C'=>'2', 'D'=>'3', 'E'=>'4', 'F'=>'5', 'G'=>'6', 'H'=>'7', + 'I'=>'8', 'J'=>'9', 'K'=>'10', 'L'=>'11', 'M'=>'12', 'N'=>'13', 'O'=>'14', 'P'=>'15', + 'Q'=>'16', 'R'=>'17', 'S'=>'18', 'T'=>'19', 'U'=>'20', 'V'=>'21', 'W'=>'22', 'X'=>'23', + 'Y'=>'24', 'Z'=>'25', '2'=>'26', '3'=>'27', '4'=>'28', '5'=>'29', '6'=>'30', '7'=>'31' + ); + + /** + * Use padding false when encoding for urls + * + * @return base32 encoded string + * @author Bryan Ruiz + **/ + public static function encode($input, $padding = true) { + if(empty($input)) return ""; + $input = str_split($input); + $binaryString = ""; + for($i = 0; $i < count($input); $i++) { + $binaryString .= str_pad(base_convert(ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT); + } + $fiveBitBinaryArray = str_split($binaryString, 5); + $base32 = ""; + $i=0; + while($i < count($fiveBitBinaryArray)) { + $base32 .= self::$map[base_convert(str_pad($fiveBitBinaryArray[$i], 5,'0'), 2, 10)]; + $i++; + } + if($padding && ($x = strlen($binaryString) % 40) != 0) { + if($x == 8) $base32 .= str_repeat(self::$map[32], 6); + else if($x == 16) $base32 .= str_repeat(self::$map[32], 4); + else if($x == 24) $base32 .= str_repeat(self::$map[32], 3); + else if($x == 32) $base32 .= self::$map[32]; + } + return $base32; + } + + public static function decode($input) { + if(empty($input)) return; + $paddingCharCount = substr_count($input, self::$map[32]); + $allowedValues = array(6,4,3,1,0); + if(!in_array($paddingCharCount, $allowedValues)) return false; + for($i=0; $i<4; $i++){ + if($paddingCharCount == $allowedValues[$i] && + substr($input, -($allowedValues[$i])) != str_repeat(self::$map[32], $allowedValues[$i])) return false; + } + $input = str_replace('=','', $input); + $input = str_split($input); + $binaryString = ""; + for($i=0; $i < count($input); $i = $i+8) { + $x = ""; + if(!in_array($input[$i], self::$map)) return false; + for($j=0; $j < 8; $j++) { + $x .= str_pad(base_convert(@self::$flippedMap[@$input[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT); + } + $eightBits = str_split($x, 8); + for($z = 0; $z < count($eightBits); $z++) { + $binaryString .= ( ($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48 ) ? $y:""; + } + } + return $binaryString; + } +} + diff --git a/vendor/OTPHP/HOTP.php b/vendor/OTPHP/HOTP.php new file mode 100644 index 00000000..7092fd9f --- /dev/null +++ b/vendor/OTPHP/HOTP.php @@ -0,0 +1,74 @@ +generateOTP($count); + } + + + /** + * Verify if a password is valid for a specific counter value + * + * @param integer $otp the one-time password + * @param integer $counter the counter value + * @return bool true if the counter is valid, false otherwise + */ + public function verify($otp, $counter) { + return ($otp == $this->at($counter)); + } + + /** + * Returns the uri for a specific secret for hotp method. + * Can be encoded as a image for simple configuration in + * Google Authenticator. + * + * @param string $name the name of the account / profile + * @param integer $initial_count the initial counter + * @return string the uri for the hmac secret + */ + public function provisioning_uri($name, $initial_count) { + return "otpauth://hotp/".urlencode($name)."?secret={$this->secret}&counter=$initial_count"; + } + } + +} diff --git a/vendor/OTPHP/LICENCE b/vendor/OTPHP/LICENCE new file mode 100644 index 00000000..d14cbc23 --- /dev/null +++ b/vendor/OTPHP/LICENCE @@ -0,0 +1,20 @@ +Copyright (c) 2011 Le Lag + +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/vendor/OTPHP/OTP.php b/vendor/OTPHP/OTP.php new file mode 100644 index 00000000..d1995ef9 --- /dev/null +++ b/vendor/OTPHP/OTP.php @@ -0,0 +1,120 @@ +digits = isset($opt['digits']) ? $opt['digits'] : 6; + $this->digest = isset($opt['digest']) ? $opt['digest'] : 'sha1'; + $this->secret = $secret; + } + + /** + * Generate a one-time password + * + * @param integer $input : number used to seed the hmac hash function. + * This number is usually a counter (HOTP) or calculated based on the current + * timestamp (see TOTP class). + * @return integer the one-time password + */ + public function generateOTP($input) { + $hash = hash_hmac($this->digest, $this->intToBytestring($input), $this->byteSecret()); + foreach(str_split($hash, 2) as $hex) { // stupid PHP has bin2hex but no hex2bin WTF + $hmac[] = hexdec($hex); + } + $offset = $hmac[19] & 0xf; + $code = ($hmac[$offset+0] & 0x7F) << 24 | + ($hmac[$offset + 1] & 0xFF) << 16 | + ($hmac[$offset + 2] & 0xFF) << 8 | + ($hmac[$offset + 3] & 0xFF); + return $code % pow(10, $this->digits); + } + + /** + * Returns the binary value of the base32 encoded secret + * @access private + * This method should be private but was left public for + * phpunit tests to work. + * @return binary secret key + */ + public function byteSecret() { + return Base32::decode($this->secret); + } + + /** + * Turns an integer in a OATH bytestring + * @param integer $int + * @access private + * @return string bytestring + */ + public function intToBytestring($int) { + $result = Array(); + while($int != 0) { + $result[] = chr($int & 0xFF); + $int >>= 8; + } + return str_pad(join(array_reverse($result)), 8, "\000", STR_PAD_LEFT); + } + } +} diff --git a/vendor/OTPHP/OTPHP.php b/vendor/OTPHP/OTPHP.php new file mode 100644 index 00000000..a6c6f8d6 --- /dev/null +++ b/vendor/OTPHP/OTPHP.php @@ -0,0 +1,27 @@ +interval = isset($opt['interval']) ? $opt['interval'] : 30; + parent::__construct($s, $opt); + } + + /** + * Get the password for a specific timestamp value + * + * @param integer $timestamp the timestamp which is timecoded and + * used to seed the hmac hash function. + * @return integer the One Time Password + */ + public function at($timestamp) { + return $this->generateOTP($this->timecode($timestamp)); + } + + /** + * Get the password for the current timestamp value + * + * @return integer the current One Time Password + */ + public function now() { + return $this->generateOTP($this->timecode(time())); + } + + /** + * Verify if a password is valid for a specific counter value + * + * @param integer $otp the one-time password + * @param integer $timestamp the timestamp for the a given time, defaults to current time. + * @return bool true if the counter is valid, false otherwise + */ + public function verify($otp, $timestamp = null) { + if($timestamp === null) + $timestamp = time(); + return ($otp == $this->at($timestamp)); + } + + /** + * Returns the uri for a specific secret for totp method. + * Can be encoded as a image for simple configuration in + * Google Authenticator. + * + * @param string $name the name of the account / profile + * @return string the uri for the hmac secret + */ + public function provisioning_uri($name) { + return "otpauth://totp/".urlencode($name)."?secret={$this->secret}"; + } + + /** + * Transform a timestamp in a counter based on specified internal + * + * @param integer $timestamp + * @return integer the timecode + */ + protected function timecode($timestamp) { + return (int)( (((int)$timestamp * 1000) / ($this->interval * 1000))); + } + } + +}