Commit e871024d authored by Amin.MasterkinG's avatar Amin.MasterkinG
Browse files

Add phpgangsta/googleauthenticator package.

parent fcc38ff3
......@@ -5,6 +5,7 @@
"rmccue/requests": "^1.7",
"phpmailer/phpmailer": "^6.0",
"gregwar/captcha": "^1.1",
"catfan/medoo": "^1.6"
"catfan/medoo": "^1.6",
"phpgangsta/googleauthenticator": "dev-master"
}
}
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "1176d28ab3f120f9387d8df9cebc8237",
"content-hash": "fdfc47f418183f38f911d2dc256490e5",
"packages": [
{
"name": "catfan/medoo",
......@@ -119,6 +119,49 @@
],
"time": "2020-01-22T14:54:02+00:00"
},
{
"name": "phpgangsta/googleauthenticator",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/PHPGangsta/GoogleAuthenticator.git",
"reference": "505c2af8337b559b33557f37cda38e5f843f3768"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPGangsta/GoogleAuthenticator/zipball/505c2af8337b559b33557f37cda38e5f843f3768",
"reference": "505c2af8337b559b33557f37cda38e5f843f3768",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"type": "library",
"autoload": {
"classmap": [
"PHPGangsta/GoogleAuthenticator.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-4-Clause"
],
"authors": [
{
"name": "Michael Kliewe",
"email": "info@phpgangsta.de",
"homepage": "http://www.phpgangsta.de/",
"role": "Developer"
}
],
"description": "Google Authenticator 2-factor authentication",
"keywords": [
"googleauthenticator",
"rfc6238",
"totp"
],
"time": "2019-03-20T00:55:58+00:00"
},
{
"name": "phpmailer/phpmailer",
"version": "v6.1.7",
......@@ -826,7 +869,9 @@
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"phpgangsta/googleauthenticator": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
......
......@@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir);
return array(
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPGangsta_GoogleAuthenticator' => $vendorDir . '/phpgangsta/googleauthenticator/PHPGangsta/GoogleAuthenticator.php',
'SebastianBergmann\\Timer\\Exception' => $vendorDir . '/phpunit/php-timer/src/Exception.php',
'SebastianBergmann\\Timer\\RuntimeException' => $vendorDir . '/phpunit/php-timer/src/RuntimeException.php',
'SebastianBergmann\\Timer\\Timer' => $vendorDir . '/phpunit/php-timer/src/Timer.php',
......
......@@ -104,6 +104,7 @@ class ComposerStaticInitde424ad7860a40a14ec11f109060d25d
public static $classMap = array (
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPGangsta_GoogleAuthenticator' => __DIR__ . '/..' . '/phpgangsta/googleauthenticator/PHPGangsta/GoogleAuthenticator.php',
'SebastianBergmann\\Timer\\Exception' => __DIR__ . '/..' . '/phpunit/php-timer/src/Exception.php',
'SebastianBergmann\\Timer\\RuntimeException' => __DIR__ . '/..' . '/phpunit/php-timer/src/RuntimeException.php',
'SebastianBergmann\\Timer\\Timer' => __DIR__ . '/..' . '/phpunit/php-timer/src/Timer.php',
......
......@@ -116,6 +116,51 @@
"spam"
]
},
{
"name": "phpgangsta/googleauthenticator",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/PHPGangsta/GoogleAuthenticator.git",
"reference": "505c2af8337b559b33557f37cda38e5f843f3768"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPGangsta/GoogleAuthenticator/zipball/505c2af8337b559b33557f37cda38e5f843f3768",
"reference": "505c2af8337b559b33557f37cda38e5f843f3768",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"time": "2019-03-20T00:55:58+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"PHPGangsta/GoogleAuthenticator.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-4-Clause"
],
"authors": [
{
"name": "Michael Kliewe",
"email": "info@phpgangsta.de",
"homepage": "http://www.phpgangsta.de/",
"role": "Developer"
}
],
"description": "Google Authenticator 2-factor authentication",
"keywords": [
"googleauthenticator",
"rfc6238",
"totp"
]
},
{
"name": "phpmailer/phpmailer",
"version": "v6.1.7",
......
# PHPStorm
.idea
# Composer
composer.lock
vendor
\ No newline at end of file
language: php
php:
- 5.5
- 5.6
install:
- export PATH="$HOME/.composer/vendor/bin:$PATH"
- composer install
script: phpunit --coverage-text --configuration tests/phpunit.xml
Copyright (c) 2012, Michael Kliewe All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<?php
/**
* PHP Class for handling Google Authenticator 2-factor authentication.
*
* @author Michael Kliewe
* @copyright 2012 Michael Kliewe
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @link http://www.phpgangsta.de/
*/
class PHPGangsta_GoogleAuthenticator
{
protected $_codeLength = 6;
/**
* Create new secret.
* 16 characters, randomly chosen from the allowed base32 characters.
*
* @param int $secretLength
*
* @return string
*/
public function createSecret($secretLength = 16)
{
$validChars = $this->_getBase32LookupTable();
// Valid secret lengths are 80 to 640 bits
if ($secretLength < 16 || $secretLength > 128) {
throw new Exception('Bad secret length');
}
$secret = '';
$rnd = false;
if (function_exists('random_bytes')) {
$rnd = random_bytes($secretLength);
} elseif (function_exists('mcrypt_create_iv')) {
$rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
} elseif (function_exists('openssl_random_pseudo_bytes')) {
$rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
if (!$cryptoStrong) {
$rnd = false;
}
}
if ($rnd !== false) {
for ($i = 0; $i < $secretLength; ++$i) {
$secret .= $validChars[ord($rnd[$i]) & 31];
}
} else {
throw new Exception('No source of secure random');
}
return $secret;
}
/**
* Calculate the code, with given secret and point in time.
*
* @param string $secret
* @param int|null $timeSlice
*
* @return string
*/
public function getCode($secret, $timeSlice = null)
{
if ($timeSlice === null) {
$timeSlice = floor(time() / 30);
}
$secretkey = $this->_base32Decode($secret);
// Pack time into binary string
$time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
// Hash it with users secret key
$hm = hash_hmac('SHA1', $time, $secretkey, true);
// Use last nipple of result as index/offset
$offset = ord(substr($hm, -1)) & 0x0F;
// grab 4 bytes of the result
$hashpart = substr($hm, $offset, 4);
// Unpak binary value
$value = unpack('N', $hashpart);
$value = $value[1];
// Only 32 bits
$value = $value & 0x7FFFFFFF;
$modulo = pow(10, $this->_codeLength);
return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
}
/**
* Get QR-Code URL for image, from google charts.
*
* @param string $name
* @param string $secret
* @param string $title
* @param array $params
*
* @return string
*/
public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
{
$width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
$height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
$level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
$urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
if (isset($title)) {
$urlencoded .= urlencode('&issuer='.urlencode($title));
}
return "https://api.qrserver.com/v1/create-qr-code/?data=$urlencoded&size=${width}x${height}&ecc=$level";
}
/**
* Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now.
*
* @param string $secret
* @param string $code
* @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
* @param int|null $currentTimeSlice time slice if we want use other that time()
*
* @return bool
*/
public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
{
if ($currentTimeSlice === null) {
$currentTimeSlice = floor(time() / 30);
}
if (strlen($code) != 6) {
return false;
}
for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
$calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
if ($this->timingSafeEquals($calculatedCode, $code)) {
return true;
}
}
return false;
}
/**
* Set the code length, should be >=6.
*
* @param int $length
*
* @return PHPGangsta_GoogleAuthenticator
*/
public function setCodeLength($length)
{
$this->_codeLength = $length;
return $this;
}
/**
* Helper class to decode base32.
*
* @param $secret
*
* @return bool|string
*/
protected function _base32Decode($secret)
{
if (empty($secret)) {
return '';
}
$base32chars = $this->_getBase32LookupTable();
$base32charsFlipped = array_flip($base32chars);
$paddingCharCount = substr_count($secret, $base32chars[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($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) {
return false;
}
}
$secret = str_replace('=', '', $secret);
$secret = str_split($secret);
$binaryString = '';
for ($i = 0; $i < count($secret); $i = $i + 8) {
$x = '';
if (!in_array($secret[$i], $base32chars)) {
return false;
}
for ($j = 0; $j < 8; ++$j) {
$x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$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;
}
/**
* Get array with all 32 characters for decoding from/encoding to base32.
*
* @return array
*/
protected function _getBase32LookupTable()
{
return array(
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
'=', // padding char
);
}
/**
* A timing safe equals comparison
* more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html.
*
* @param string $safeString The internal (safe) value to be checked
* @param string $userString The user submitted (unsafe) value
*
* @return bool True if the two strings are identical
*/
private function timingSafeEquals($safeString, $userString)
{
if (function_exists('hash_equals')) {
return hash_equals($safeString, $userString);
}
$safeLen = strlen($safeString);
$userLen = strlen($userString);
if ($userLen != $safeLen) {
return false;
}
$result = 0;
for ($i = 0; $i < $userLen; ++$i) {
$result |= (ord($safeString[$i]) ^ ord($userString[$i]));
}
// They are only identical strings if $result is exactly 0...
return $result === 0;
}
}
Google Authenticator PHP class
==============================
* Copyright (c) 2012-2016, [http://www.phpgangsta.de](http://www.phpgangsta.de)
* Author: Michael Kliewe, [@PHPGangsta](http://twitter.com/PHPGangsta) and [contributors](https://github.com/PHPGangsta/GoogleAuthenticator/graphs/contributors)
* Licensed under the BSD License.
[![Build Status](https://travis-ci.org/PHPGangsta/GoogleAuthenticator.png?branch=master)](https://travis-ci.org/PHPGangsta/GoogleAuthenticator)
This PHP class can be used to interact with the Google Authenticator mobile app for 2-factor-authentication. This class
can generate secrets, generate codes, validate codes and present a QR-Code for scanning the secret. It implements TOTP
according to [RFC6238](https://tools.ietf.org/html/rfc6238)
For a secure installation you have to make sure that used codes cannot be reused (replay-attack). You also need to
limit the number of verifications, to fight against brute-force attacks. For example you could limit the amount of
verifications to 10 tries within 10 minutes for one IP address (or IPv6 block). It depends on your environment.
Usage:
------
See following example:
```php
<?php
require_once 'PHPGangsta/GoogleAuthenticator.php';
$ga = new PHPGangsta_GoogleAuthenticator();
$secret = $ga->createSecret();
echo "Secret is: ".$secret."\n\n";
$qrCodeUrl = $ga->getQRCodeGoogleUrl('Blog', $secret);
echo "Google Charts URL for the QR-Code: ".$qrCodeUrl."\n\n";
$oneCode = $ga->getCode($secret);
echo "Checking Code '$oneCode' and Secret '$secret':\n";
$checkResult = $ga->verifyCode($secret, $oneCode, 2); // 2 = 2*30sec clock tolerance
if ($checkResult) {
echo 'OK';
} else {
echo 'FAILED';
}
```
Running the script provides the following output:
```
Secret is: OQB6ZZGYHCPSX4AK
Google Charts URL for the QR-Code: https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/infoATphpgangsta.de%3Fsecret%3DOQB6ZZGYHCPSX4AK
Checking Code '848634' and Secret 'OQB6ZZGYHCPSX4AK':
OK
```
Installation:
-------------
- Use [Composer](https://getcomposer.org/doc/01-basic-usage.md) to
install the package
- From project root directory execute following
```composer install```
- [Composer](https://getcomposer.org/doc/01-basic-usage.md) will take care of autoloading
the library. Just include the following at the top of your file
`require_once __DIR__ . '/../vendor/autoload.php';`
Run Tests:
----------
- All tests are inside `tests` folder.
- Execute `composer install` and then run the tests from project root
directory
- Run as `phpunit tests` from the project root directory
ToDo:
-----
- ??? What do you need?
Notes:
------
If you like this script or have some features to add: contact me, visit my blog, fork this project, send pull requests, you know how it works.
{
"name": "phpgangsta/googleauthenticator",
"description": "Google Authenticator 2-factor authentication",
"version": "1.0.0",
"type": "library",
"keywords": ["GoogleAuthenticator", "TOTP", "rfc6238"],
"license": "BSD-4-Clause",
"authors": [
{
"name": "Michael Kliewe",
"email": "info@phpgangsta.de",
"homepage": "http://www.phpgangsta.de/",
"role": "Developer"
}
],
"support": {
"source": "https://github.com/PHPGangsta/GoogleAuthenticator",
"issues": "https://github.com/PHPGangsta/GoogleAuthenticator/issues"
},
"require": {
"php": ">=5.3"
},
"autoload": {
"classmap": ["PHPGangsta/GoogleAuthenticator.php"]
}
}
<?php
require_once __DIR__.'/../vendor/autoload.php';
class GoogleAuthenticatorTest extends PHPUnit_Framework_TestCase
{
/* @var $googleAuthenticator PHPGangsta_GoogleAuthenticator */
protected $googleAuthenticator;
protected function setUp()
{
$this->googleAuthenticator = new PHPGangsta_GoogleAuthenticator();
}
public function codeProvider()
{
// Secret, time, code
return array(
array('SECRET', '0', '200470'),
array('SECRET', '1385909245', '780018'),
array('SECRET', '1378934578', '705013'),
);
}
public function testItCanBeInstantiated()