init web ems all

This commit is contained in:
agtuser
2024-09-27 17:13:36 +08:00
parent 81c97acbe9
commit 5cc56f8078
4263 changed files with 798779 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
checks:
php:
remove_extra_empty_lines: true
remove_php_closing_tag: true
remove_trailing_whitespace: true
fix_use_statements:
remove_unused: true
preserve_multiple: false
preserve_blanklines: true
order_alphabetically: true
fix_php_opening_tag: true
fix_linefeed: true
fix_line_ending: true
fix_identation_4spaces: true
fix_doc_comments: true
filter:
paths: [src/*]
excluded_paths: [tests/*]
coding_style:
php: { }
build:
tests:
override:
-
command: 'vendor/bin/phpunit -c phpunit.xml'
coverage:
file: 'coverage/coverage-clover.xml'
format: 'clover'
nodes:
analysis:
tests:
override:
- php-scrutinizer-run
tests: true
tools:
external_code_coverage: true

View File

@@ -0,0 +1,33 @@
dist: trusty
language: php
php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
- nightly
# This triggers builds to run on the new TravisCI infrastructure.
# See: http://docs.travis-ci.com/user/workers/container-based-infrastructure/
sudo: false
## Cache composer
cache:
directories:
- $HOME/.composer/cache
before_script:
- travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist
script:
- vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover
after_script:
- |
if [[ "$TRAVIS_PHP_VERSION" == '7.2' ]]; then
wget https://scrutinizer-ci.com/ocular.phar
php ocular.phar code-coverage:upload --format=php-clover coverage.clover
fi

View File

@@ -0,0 +1,7 @@
Copyright 2014-2018 Phil, Antonio Carlos Ribeiro and All Contributors
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.

276
phpMyAdmin/vendor/pragmarx/google2fa/README.md vendored Executable file
View File

@@ -0,0 +1,276 @@
# Google2FA
<p align="center">
<a href="https://packagist.org/packages/pragmarx/google2fa"><img alt="Latest Stable Version" src="https://img.shields.io/packagist/v/pragmarx/google2fa.svg?style=flat-square"></a>
<a href="LICENSE.md"><img alt="License" src="https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square"></a>
<a href="https://scrutinizer-ci.com/g/antonioribeiro/google2fa/?branch=master"><img alt="Code Quality" src="https://img.shields.io/scrutinizer/g/antonioribeiro/google2fa.svg?style=flat-square"></a>
<a href="https://travis-ci.org/antonioribeiro/google2fa"><img alt="Build" src="https://img.shields.io/travis/antonioribeiro/google2fa.svg?style=flat-square"></a>
</p>
<p align="center">
<a href="https://packagist.org/packages/pragmarx/google2fa"><img alt="Downloads" src="https://img.shields.io/packagist/dt/pragmarx/google2fa.svg?style=flat-square"></a>
<a href="https://scrutinizer-ci.com/g/antonioribeiro/google2fa/?branch=master"><img alt="Coverage" src="https://img.shields.io/scrutinizer/coverage/g/antonioribeiro/google2fa.svg?style=flat-square"></a>
<a href="https://styleci.io/repos/24296182"><img alt="StyleCI" src="https://styleci.io/repos/24296182/shield"></a>
<a href="https://travis-ci.org/antonioribeiro/google2fa"><img alt="PHP" src="https://img.shields.io/badge/PHP-5.4%20--%207.2-brightgreen.svg?style=flat-square"></a>
</p>
### Google Two-Factor Authentication for PHP Package
Google2FA is a PHP implementation of the Google Two-Factor Authentication Module, supporting the HMAC-Based One-time Password (HOTP) algorithm specified in [RFC 4226](https://tools.ietf.org/html/rfc4226) and the Time-based One-time Password (TOTP) algorithm specified in [RFC 6238](https://tools.ietf.org/html/rfc6238).
This package is agnostic, but there's a [Laravel bridge](https://github.com/antonioribeiro/google2fa-laravel).
## Demos, Example & Playground
Please check the [Google2FA Package Playground](http://pragmarx.com/playground/google2fa).
![playground](docs/playground.jpg)
Here's an demo app showing how to use Google2FA: [google2fa-example](https://github.com/antonioribeiro/google2fa-example).
You can scan the QR code on [this (old) demo page](https://antoniocarlosribeiro.com/technology/google2fa) with a Google Authenticator app and view the code changing (almost) in real time.
## Requirements
- PHP 5.4+
## Installing
Use Composer to install it:
composer require pragmarx/google2fa
If you prefer inline QRCodes instead of a Google generated url, you'll need to install [BaconQrCode](https://github.com/Bacon/BaconQrCode):
composer require bacon/bacon-qr-code
## Using It
### Instantiate it directly
```php
use PragmaRX\Google2FA\Google2FA;
$google2fa = new Google2FA();
return $google2fa->generateSecretKey();
```
## How To Generate And Use Two Factor Authentication
Generate a secret key for your user and save it:
```php
$user->google2fa_secret = $google2fa->generateSecretKey();
```
## Generating QRCodes
The securer way of creating QRCode is to do it yourself or using a library. First you have to install the BaconQrCode package, as stated above, then you just have to generate the inline string using:
```php
$inlineUrl = $google2fa->getQRCodeInline(
$companyName,
$companyEmail,
$secretKey
);
```
And use it in your blade template this way:
```html
<img src="{{ $inlineUrl }}">
```
```php
$secretKey = $google2fa->generateSecretKey(16, $userId);
```
## Show the QR Code to your user, via Google Apis
It's insecure to use it via Google Apis, so you have to enable it before using it.
```php
$google2fa->setAllowInsecureCallToGoogleApis(true);
$google2fa_url = $google2fa->getQRCodeGoogleUrl(
'YourCompany',
$user->email,
$user->google2fa_secret
);
/// and in your view:
<img src="{{ $google2fa_url }}" alt="">
```
And they should see and scan the QR code to their applications:
![QRCode](https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth%3A%2F%2Ftotp%2FPragmaRX%3Aacr%2Bpragmarx%40antoniocarlosribeiro.com%3Fsecret%3DADUMJO5634NPDEKW%26issuer%3DPragmaRX)
And to verify, you just have to:
```php
$secret = $request->input('secret');
$valid = $google2fa->verifyKey($user->google2fa_secret, $secret);
```
## QR Code Packages
This package suggests the use of Bacon/QRCode because it is known as a good QR Code package, but you can use it with any other package, for instance [Simple QrCode](https://www.simplesoftware.io/docs/simple-qrcode), which uses Bacon/QRCode to produce QR Codes.
Usually you'll need a 2FA URL, so you just have to use the URL generator:
```php
$google2fa->getQRCodeUrl($companyName, $companyEmail, $secretKey)
```
Here's an example using Simple QrCode:
```php
<div class="visible-print text-center">
{!! QrCode::size(100)->generate($google2fa->getQRCodeUrl($companyName, $companyEmail, $secretKey)); !!}
<p>Scan me to return to the original page.</p>
</div>
```
## Server Time
It's really important that you keep your server time in sync with some NTP server, on Ubuntu you can add this to the crontab:
sudo service ntp stop
sudo ntpd -gq
sudo service ntp start
## Validation Window
To avoid problems with clocks that are slightly out of sync, we do not check against the current key only but also consider `$window` keys each from the past and future. You can pass `$window` as optional third parameter to `verifyKey`, it defaults to `4`. A new key is generated every 30 seconds, so this window includes keys from the previous two and next two minutes.
```php
$secret = $request->input('secret');
$window = 8; // 8 keys (respectively 4 minutes) past and future
$valid = $google2fa->verifyKey($user->google2fa_secret, $secret, $window);
```
An attacker might be able to watch the user entering his credentials and one time key.
Without further precautions, the key remains valid until it is no longer within the window of the server time. In order to prevent usage of a one time key that has already been used, you can utilize the `verifyKeyNewer` function.
```php
$secret = $request->input('secret');
$timestamp = $google2fa->verifyKeyNewer($user->google2fa_secret, $secret, $user->google2fa_ts);
if ($timestamp !== false) {
$user->update(['google2fa_ts' => $timestamp]);
// successful
} else {
// failed
}
```
Note that `$timestamp` either `false` (if the key is invalid or has been used before) or the provided key's unix timestamp divided by the key regeneration period of 30 seconds.
## Using a Bigger and Prefixing the Secret Key
Although the probability of collision of a 16 bytes (128 bits) random string is very low, you can harden it by:
#### Use a bigger key
```php
$secretKey = $google2fa->generateSecretKey(32); // defaults to 16 bytes
```
#### You cn prefix your secret keys
You may prefix your secret keys, but you have to understand that, as your secret key must have length in power of 2, your prefix will have to have a complementary size. So if your key is 16 bytes long, if you add a prefix it must be also 16 bytes long, but as your prefixes will be converted to base 32, the max length of your prefix is 10 bytes. So, those are the sizes you can use in your prefixes:
```
1, 2, 5, 10, 20, 40, 80...
```
And it can be used like so:
```php
$prefix = strpad($userId, 10, 'X');
$secretKey = $google2fa->generateSecretKey(16, $prefix);
```
#### Window
The Window property defines how long a OTP will work, or how many cycles it will last. A key has a 30 seconds cycle, setting the window to 0 will make the key lasts for those 30 seconds, setting it to 2 will make it last for 120 seconds. This is how you set the window:
```php
$secretKey = $google2fa->setWindow(4);
```
But you can also set the window while checking the key. If you need to set a window of 4 during key verification, this is how you do:
```php
$isValid = $google2fa->verifyKey($seed, $key, 4);
```
#### Key Regeneration Interval
You can change key regeneration interval, which defaults to 30 seconds, but remember that this is a default value on most authentication apps, like Google Authenticator, which will, basically, make your app out of sync with them.
```php
$google2fa->setKeyRegeneration(40);
```
## Google Authenticator secret key compatibility
To be compatible with Google Authenticator, your (converted to base 32) secret key length must be at least 8 chars and be a power of 2: 8, 16, 32, 64...
So, to prevent errors, you can do something like this while generating it:
```php
$secretKey = '123456789';
$secretKey = str_pad($secretKey, pow(2,ceil(log(strlen($secretKey),2))), 'X');
```
And it will generate
```
123456789XXXXXXX
```
By default, this package will enforce compatibility, but, if Google Authenticator is not a target, you can disable it by doing
```php
$google2fa->setEnforceGoogleAuthenticatorCompatibility(false);
```
## Google Authenticator Apps:
To use the two factor authentication, your user will have to install a Google Authenticator compatible app, those are some of the currently available:
* [Authy for iOS, Android, Chrome, OS X](https://www.authy.com/)
* [FreeOTP for iOS, Android and Pebble](https://apps.getpebble.com/en_US/application/52f1a4c3c4117252f9000bb8)
* [Google Authenticator for iOS](https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8)
* [Google Authenticator for Android](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2)
* [Google Authenticator (port) on Windows Store](https://www.microsoft.com/en-us/store/p/google-authenticator/9wzdncrdnkrf)
* [Microsoft Authenticator for Windows Phone](https://www.microsoft.com/en-us/store/apps/authenticator/9wzdncrfj3rj)
* [LastPass Authenticator for iOS, Android, OS X, Windows](https://lastpass.com/auth/)
* [1Password for iOS, Android, OS X, Windows](https://1password.com)
## Tests
The package tests were written with [phpspec](http://www.phpspec.net/en/latest/).
## Authors
- [Antonio Carlos Ribeiro](http://twitter.com/iantonioribeiro)
- [Phil (Orginal author of this class)](https://www.idontplaydarts.com/static/ga.php_.txt)
- [All Contributors](https://github.com/antonioribeiro/google2fa/graphs/contributors)
## License
Google2FA is licensed under the MIT License - see the [LICENSE](LICENSE.md) file for details.
## Contributing
Pull requests and issues are more than welcome.

View File

@@ -0,0 +1,29 @@
# Package Relicensed
As per [Issue #100](https://github.com/antonioribeiro/google2fa/issues/100) the relicensing of this package from GPLv3 to MIT was approved by the original developer of the Google2FA class (Phil) and the majority of the contributors, by contributions, of this package.
# Original License
``` php
/**
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* PHP Google two-factor authentication module.
*
* See https://www.idontplaydarts.com/2011/07/google-totp-two-factor-authentication-for-php/
* for more details
*
* @author Phil
**/
```

View File

@@ -0,0 +1,69 @@
## Change Log
## [3.0.1] - 2018-03-15
### Changed
- Relicensed to MIT
## [3.0.0] - 2018-03-07
### Changed
- It's now mandatory to enable Google Api secret key access by executing `setAllowInsecureCallToGoogleApis(true);`
## [2.0.4] - 2017-06-22
### Fixed
- Fix Base32 to keep supporting PHP 5.4 && 5.5.
## [2.0.3] - 2017-06-22
## [2.0.2] - 2017-06-21
## [2.0.1] - 2017-06-20
### Fixed
- Minor bugs
## [2.0.0] - 2017-06-20
### Changed
- Drop the Laravel support in favor of a bridge package (https://github.com/antonioribeiro/google2fa-laravel).
- Using a more secure Base 32 algorithm, to prevent cache-timing attacks.
- Added verifyKeyNewer() method to prevent reuse of keys.
- Refactored to remove complexity, by extracting support methods.
- Created a package playground page (https://pragmarx.com/google2fa)
## [2.0.0] - 2017-06-20
### Changed
- Drop the Laravel support in favor of a bridge package (https://github.com/antonioribeiro/google2fa-laravel).
- Using a more secure Base 32 algorithm, to prevent cache-timing attacks.
- Added verifyKeyNewer() method to prevent reuse of keys.
- Refactored to remove complexity, by extracting support methods.
- Created a package playground page (https://pragmarx.com/google2fa)
## [1.0.1] - 2016-07-18
### Changed
- Drop support for PHP 5.3.7, require PHP 5.4+.
- Coding style is now PSR-2 automatically enforced by StyleCI.
## [1.0.0] - 2016-07-17
### Changed
- Package bacon/bacon-qr-code was moved to "suggest".
## [0.8.1] - 2016-07-17
### Fixed
- Allow paragonie/random_compat ~1.4|~2.0.
## [0.8.0] - 2016-07-17
### Changed
- Bumped christian-riesen/base32 to ~1.3
- Use paragonie/random_compat to generate cryptographically secure random secret keys
- Readme improvements
- Drop simple-qrcode in favor of bacon/bacon-qr-code
- Fix tavis setup for phpspec, PHP 7, hhvm and improve cache
## [0.7.0] - 2015-11-07
### Changed
- Fixed URL generation for QRCodes
- Avoid time attacks
## [0.2.0] - 2015-02-19
### Changed
- Laravel 5 compatibility.
## [0.1.0] - 2014-07-06
### Added
- First version.

View File

@@ -0,0 +1,40 @@
{
"name": "pragmarx/google2fa",
"description": "A One Time Password Authentication package, compatible with Google Authenticator.",
"keywords": ["authentication", "two factor authentication", "google2fa", "laravel", "2fa"],
"license": "MIT",
"authors": [
{
"name": "Antonio Carlos Ribeiro",
"email": "acr@antoniocarlosribeiro.com",
"role": "Creator & Designer"
}
],
"require": {
"php": ">=5.4",
"paragonie/constant_time_encoding": "~1.0|~2.0",
"paragonie/random_compat": ">=1",
"symfony/polyfill-php56": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "~4|~5|~6",
"bacon/bacon-qr-code": "~1.0"
},
"autoload": {
"psr-4": {
"PragmaRX\\Google2FA\\": "src/",
"PragmaRX\\Google2FA\\Tests\\": "tests/"
}
},
"extra": {
"component": "package",
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"suggest": {
"bacon/bacon-qr-code": "Required to generate inline QR Codes."
},
"minimum-stability": "dev",
"prefer-stable": true
}

1742
phpMyAdmin/vendor/pragmarx/google2fa/composer.lock generated vendored Executable file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="tests/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
syntaxCheck="true"
verbose="true"
>
<testsuites>
<testsuite name="Laravel Test Suite">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-html" target="coverage/" lowUpperBound="35" highLowerBound="70"/>
<log type="coverage-clover" target="coverage/coverage-clover.xml" lowUpperBound="35" highLowerBound="70"/>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="true"/>
</logging>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true" processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
<exclude></exclude>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,10 @@
<?php
namespace PragmaRX\Google2FA\Exceptions;
use Exception;
class IncompatibleWithGoogleAuthenticatorException extends Exception
{
protected $message = 'This secret key is not compatible with Google Authenticator.';
}

View File

@@ -0,0 +1,10 @@
<?php
namespace PragmaRX\Google2FA\Exceptions;
use Exception;
class InsecureCallException extends Exception
{
protected $message = 'It\'s not secure to send secret keys to Google Apis, you have to explicitly allow it by calling $google2fa->setAllowInsecureCallToGoogleApis(true).';
}

View File

@@ -0,0 +1,10 @@
<?php
namespace PragmaRX\Google2FA\Exceptions;
use Exception;
class InvalidCharactersException extends Exception
{
protected $message = 'Invalid characters in the base32 string.';
}

View File

@@ -0,0 +1,10 @@
<?php
namespace PragmaRX\Google2FA\Exceptions;
use Exception;
class SecretKeyTooShortException extends Exception
{
protected $message = 'Secret key is too short. Must be at least 16 base32 characters';
}

View File

@@ -0,0 +1,354 @@
<?php
namespace PragmaRX\Google2FA;
use PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException;
use PragmaRX\Google2FA\Support\Base32;
use PragmaRX\Google2FA\Support\Constants;
use PragmaRX\Google2FA\Support\QRCode;
class Google2FA
{
use QRCode, Base32;
/**
* Length of the Token generated.
*/
protected $oneTimePasswordLength = 6;
/**
* Interval between key regeneration.
*/
protected $keyRegeneration = 30;
/**
* Secret.
*/
protected $secret;
/**
* Window.
*/
protected $window = 1; // Keys will be valid for 60 seconds
/**
* Find a valid One Time Password.
*
* @param $secret
* @param $key
* @param $window
* @param $startingTimestamp
* @param $timestamp
* @param string $oldTimestamp
*
* @return bool
*/
public function findValidOTP($secret, $key, $window, $startingTimestamp, $timestamp, $oldTimestamp = Constants::ARGUMENT_NOT_SET)
{
for (; $startingTimestamp <= $timestamp + $this->getWindow($window); $startingTimestamp++) {
if (hash_equals($this->oathHotp($secret, $startingTimestamp), $key)) {
return
$oldTimestamp === Constants::ARGUMENT_NOT_SET
? true
: $startingTimestamp;
}
}
return false;
}
/**
* Generate a digit secret key in base32 format.
*
* @param int $length
* @param string $prefix
*
* @return string
*/
public function generateSecretKey($length = 16, $prefix = '')
{
return $this->generateBase32RandomKey($length, $prefix);
}
/**
* Get the current one time password for a key.
*
* @param $secret
*
* @return string
*/
public function getCurrentOtp($secret)
{
return $this->oathHotp($secret, $this->getTimestamp());
}
/**
* Get key regeneration.
*
* @return mixed
*/
public function getKeyRegeneration()
{
return $this->keyRegeneration;
}
/**
* Get OTP length.
*
* @return mixed
*/
public function getOneTimePasswordLength()
{
return $this->oneTimePasswordLength;
}
/**
* Get secret.
*
* @param string|null $secret
*
* @return mixed
*/
public function getSecret($secret = null)
{
return
is_null($secret)
? $this->secret
: $secret;
}
/**
* Returns the current Unix Timestamp divided by the $keyRegeneration
* period.
*
* @return int
**/
public function getTimestamp()
{
return (int) floor(microtime(true) / $this->keyRegeneration);
}
/**
* Get the OTP window.
*
* @param null|int $window
*
* @return mixed
*/
public function getWindow($window = null)
{
return
is_null($window)
? $this->window
: $window;
}
/**
* Make a window based starting timestamp.
*
* @param $window
* @param $timestamp
* @param $oldTimestamp
*
* @return mixed
*/
private function makeStartingTimestamp($window, $timestamp, $oldTimestamp)
{
return $oldTimestamp === Constants::ARGUMENT_NOT_SET
? $timestamp - $this->getWindow($window)
: max($timestamp - $this->getWindow($window), $oldTimestamp + 1);
}
/**
* Get/use a starting timestamp for key verification.
*
* @param string|int|null $timestamp
*
* @return int
*/
protected function makeTimestamp($timestamp = null)
{
if (is_null($timestamp)) {
return $this->getTimestamp();
}
return (int) $timestamp;
}
/**
* Takes the secret key and the timestamp and returns the one time
* password.
*
* @param string $secret - Secret key in binary form.
* @param int $counter - Timestamp as returned by getTimestamp.
*
* @throws SecretKeyTooShortException
*
* @return string
*/
public function oathHotp($secret, $counter)
{
$secret = $this->base32Decode($this->getSecret($secret));
if (strlen($secret) < 8) {
throw new SecretKeyTooShortException();
}
// Counter must be 64-bit int
$bin_counter = pack('N*', 0, $counter);
$hash = hash_hmac('sha1', $bin_counter, $secret, true);
return str_pad($this->oathTruncate($hash), $this->getOneTimePasswordLength(), '0', STR_PAD_LEFT);
}
/**
* Extracts the OTP from the SHA1 hash.
*
* @param string $hash
*
* @return int
**/
public function oathTruncate($hash)
{
$offset = ord($hash[19]) & 0xf;
$temp = unpack('N', substr($hash, $offset, 4));
return substr($temp[1] & 0x7fffffff, -$this->getOneTimePasswordLength());
}
/**
* Remove invalid chars from a base 32 string.
*
* @param $string
*
* @return mixed
*/
public function removeInvalidChars($string)
{
return preg_replace('/[^'.Constants::VALID_FOR_B32.']/', '', $string);
}
/**
* Setter for the enforce Google Authenticator compatibility property.
*
* @param mixed $enforceGoogleAuthenticatorCompatibility
*
* @return $this
*/
public function setEnforceGoogleAuthenticatorCompatibility($enforceGoogleAuthenticatorCompatibility)
{
$this->enforceGoogleAuthenticatorCompatibility = $enforceGoogleAuthenticatorCompatibility;
return $this;
}
/**
* Set key regeneration.
*
* @param mixed $keyRegeneration
*/
public function setKeyRegeneration($keyRegeneration)
{
$this->keyRegeneration = $keyRegeneration;
}
/**
* Set OTP length.
*
* @param mixed $oneTimePasswordLength
*/
public function setOneTimePasswordLength($oneTimePasswordLength)
{
$this->oneTimePasswordLength = $oneTimePasswordLength;
}
/**
* Set secret.
*
* @param mixed $secret
*/
public function setSecret($secret)
{
$this->secret = $secret;
}
/**
* Set the OTP window.
*
* @param mixed $window
*/
public function setWindow($window)
{
$this->window = $window;
}
/**
* Verifies a user inputted key against the current timestamp. Checks $window
* keys either side of the timestamp.
*
* @param string $key - User specified key
* @param null|string $secret
* @param null|int $window
* @param null|int $timestamp
* @param null|string|int $oldTimestamp
*
* @return bool|int
*/
public function verify($key, $secret = null, $window = null, $timestamp = null, $oldTimestamp = Constants::ARGUMENT_NOT_SET)
{
return $this->verifyKey(
$secret,
$key,
$window,
$timestamp,
$oldTimestamp
);
}
/**
* Verifies a user inputted key against the current timestamp. Checks $window
* keys either side of the timestamp.
*
* @param string $secret
* @param string $key - User specified key
* @param null|int $window
* @param null|int $timestamp
* @param null|string|int $oldTimestamp
*
* @return bool|int
*/
public function verifyKey($secret, $key, $window = null, $timestamp = null, $oldTimestamp = Constants::ARGUMENT_NOT_SET)
{
$timestamp = $this->makeTimestamp($timestamp);
return $this->findValidOTP(
$secret,
$key,
$window,
$this->makeStartingTimestamp($window, $timestamp, $oldTimestamp),
$timestamp,
$oldTimestamp
);
}
/**
* Verifies a user inputted key against the current timestamp. Checks $window
* keys either side of the timestamp, but ensures that the given key is newer than
* the given oldTimestamp. Useful if you need to ensure that a single key cannot
* be used twice.
*
* @param string $secret
* @param string $key - User specified key
* @param int $oldTimestamp - The timestamp from the last verified key
* @param int|null $window
* @param int|null $timestamp
*
* @return bool|int - false (not verified) or the timestamp of the verified key
**/
public function verifyKeyNewer($secret, $key, $oldTimestamp, $window = null, $timestamp = null)
{
return $this->verifyKey($secret, $key, $window, $timestamp, $oldTimestamp);
}
}

View File

@@ -0,0 +1,135 @@
<?php
namespace PragmaRX\Google2FA\Support;
use ParagonIE\ConstantTime\Base32 as ParagonieBase32;
use PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException;
use PragmaRX\Google2FA\Exceptions\InvalidCharactersException;
trait Base32
{
/**
* Enforce Google Authenticator compatibility.
*/
protected $enforceGoogleAuthenticatorCompatibility = true;
/**
* Generate a digit secret key in base32 format.
*
* @param int $length
*
* @return string
*/
public function generateBase32RandomKey($length = 16, $prefix = '')
{
$secret = $prefix ? $this->toBase32($prefix) : '';
$secret = $this->strPadBase32($secret, $length);
$this->validateSecret($secret);
return $secret;
}
/**
* Decodes a base32 string into a binary string.
*
* @param string $b32
*
* @throws InvalidCharactersException
*
* @return int
*/
public function base32Decode($b32)
{
$b32 = strtoupper($b32);
$this->validateSecret($b32);
return ParagonieBase32::decodeUpper($b32);
}
/**
* Pad string with random base 32 chars.
*
* @param $string
* @param $length
*
* @return string
*/
private function strPadBase32($string, $length)
{
for ($i = 0; $i < $length; $i++) {
$string .= substr(Constants::VALID_FOR_B32_SCRAMBLED, $this->getRandomNumber(), 1);
}
return $string;
}
/**
* Encode a string to Base32.
*
* @param $string
*
* @return mixed
*/
public function toBase32($string)
{
$encoded = ParagonieBase32::encodeUpper($string);
return str_replace('=', '', $encoded);
}
/**
* Get a random number.
*
* @param $from
* @param $to
*
* @return int
*/
protected function getRandomNumber($from = 0, $to = 31)
{
return random_int($from, $to);
}
/**
* Validate the secret.
*
* @param $b32
*/
protected function validateSecret($b32)
{
$this->checkForValidCharacters($b32);
$this->checkGoogleAuthenticatorCompatibility($b32);
}
/**
* Check if the secret key is compatible with Google Authenticator.
*
* @param $b32
*
* @throws IncompatibleWithGoogleAuthenticatorException
*/
protected function checkGoogleAuthenticatorCompatibility($b32)
{
if ($this->enforceGoogleAuthenticatorCompatibility && ((strlen($b32) & (strlen($b32) - 1)) !== 0)) {
throw new IncompatibleWithGoogleAuthenticatorException();
}
}
/**
* Check if all secret key characters are valid.
*
* @param $b32
*
* @throws InvalidCharactersException
*/
protected function checkForValidCharacters($b32)
{
if (preg_replace('/[^'.Constants::VALID_FOR_B32.']/', '', $b32) !== $b32) {
throw new InvalidCharactersException();
}
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace PragmaRX\Google2FA\Support;
class Constants
{
/**
* Characters valid for Base 32.
*/
const VALID_FOR_B32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
/**
* Characters valid for Base 32, scrambled.
*/
const VALID_FOR_B32_SCRAMBLED = '234567QWERTYUIOPASDFGHJKLZXCVBNM';
/**
* Argument not set constant.
*/
const ARGUMENT_NOT_SET = '__not_set__';
}

View File

@@ -0,0 +1,91 @@
<?php
namespace PragmaRX\Google2FA\Support;
use BaconQrCode\Renderer\Image\Png;
use BaconQrCode\Writer as BaconQrCodeWriter;
use PragmaRX\Google2FA\Exceptions\InsecureCallException;
trait QRCode
{
/**
* Sending your secret key to Google API is a security issue. Developer must explicitly allow it.
*/
protected $allowInsecureCallToGoogleApis = false;
/**
* Creates a Google QR code url.
*
* @param string $company
* @param string $holder
* @param string $secret
* @param int $size
*
* @throws InsecureCallException
*
* @return string
*/
public function getQRCodeGoogleUrl($company, $holder, $secret, $size = 200)
{
if (!$this->allowInsecureCallToGoogleApis) {
throw new InsecureCallException('It\'s not secure to send secret keys to Google Apis, you have to explicitly allow it by calling $google2fa->setAllowInsecureCallToGoogleApis(true).');
}
$url = $this->getQRCodeUrl($company, $holder, $secret);
return Url::generateGoogleQRCodeUrl('https://chart.googleapis.com/', 'chart', 'chs='.$size.'x'.$size.'&chld=M|0&cht=qr&chl=', $url);
}
/**
* Generates a QR code data url to display inline.
*
* @param string $company
* @param string $holder
* @param string $secret
* @param int $size
* @param string $encoding Default to UTF-8
*
* @return string
*/
public function getQRCodeInline($company, $holder, $secret, $size = 200, $encoding = 'utf-8')
{
$url = $this->getQRCodeUrl($company, $holder, $secret);
$renderer = new Png();
$renderer->setWidth($size);
$renderer->setHeight($size);
$bacon = new BaconQrCodeWriter($renderer);
$data = $bacon->writeString($url, $encoding);
return 'data:image/png;base64,'.base64_encode($data);
}
/**
* Creates a QR code url.
*
* @param $company
* @param $holder
* @param $secret
*
* @return string
*/
public function getQRCodeUrl($company, $holder, $secret)
{
return 'otpauth://totp/'.rawurlencode($company).':'.rawurlencode($holder).'?secret='.$secret.'&issuer='.rawurlencode($company).'';
}
/**
* AllowInsecureCallToGoogleApis setter.
*
* @param mixed $allowInsecureCallToGoogleApis
*
* @return QRCode
*/
public function setAllowInsecureCallToGoogleApis($allowInsecureCallToGoogleApis)
{
$this->allowInsecureCallToGoogleApis = $allowInsecureCallToGoogleApis;
return $this;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace PragmaRX\Google2FA\Support;
class Url
{
public static function generateGoogleQRCodeUrl($domain, $page, $queryParameters, $qrCodeUrl)
{
$url = $domain.
rawurlencode($page).
'?'.$queryParameters.
urlencode($qrCodeUrl);
return $url;
}
}

View File

View File

@@ -0,0 +1,20 @@
<?php
namespace PragmaRX\Google2FA\Tests;
class Constants
{
const SECRET = 'ADUMJO5634NPDEKW';
const SHORT_SECRET = 'ADUMJO5';
const INVALID_SECRET = 'DUMJO5634NPDEKX@';
const WRONG_SECRET = 'ADUMJO5634NPDEKX';
const URL = 'https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth%3A%2F%2Ftotp%2FPragmaRX%3Aacr%252Bpragmarx%2540antoniocarlosribeiro.com%3Fsecret%3DADUMJO5634NPDEKW%26issuer%3DPragmaRX';
const QRCODEPHPABOVE72 = 'data:image/png;base64,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';
const QRCODEPHPBELOW72 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAFjklEQVR4nO3dwY6dOhBF0ZdW/v+TW28WMbhWV1Fn25DsNYzAkOSIW7JN8ev7+/s/Ke3r9A3o72SwhDBYQhgsIQyWEAZLCIMlhMESwmAJYbCEMFhCGCwhDJYQBksIgyWEwRLCYAnx+95pX1/5RE72sq7upzLm9dzJ8ZN7qFyrMuZz/l98YglhsIQwWELcrLGuiBqiWyusah269uoeU3EdZ3Jd4v+lMcLwfOkjgyWEwRIiUGNdVX6bK7/9q5opVUt1a7vuPVTqpMp1u8dMzs2+E+8TSwiDJYTBEiJcY6VUappU7dIdZzK/1a2Tun/f5/CJJYTBEsJgCfHQGitVT3Trs8pcVGp9s4vY78XxiSWEwRLCYAkRrrFSv/eT+ZvJuttkXio1p5Waw7vaX4f5xBLCYAlhsIQI1Fj0/E33Hrp7uVJ1zM77IfbaZ53PhP5KBksIgyXEzRqLnheZzPdUxunukUrNG+38dzvLJ5YQBksIgyXEgf5Yk/pmsme88udEP63KdbtOzY3V+cQSwmAJYbCECPfHIvpznuqrmeqVMJnTmvS56MrWWz6xhDBYQhgsIX6FuyIN9gntn2vJ3ltlnJXJfBgxl+Y8lh7KYAlhsIS4WWN1a5EVYn/3zj3jp+4z1XOV+xaQTywhDJYQBkuIcI21Mvnt795D6rs3k2Mqx+/8vmFq/MadbLiG/kEGSwiDJURgrXBnXTK5t5VT9VzFznm4ynXrfGIJYbCEMFhCHHivcDUO/Y4e0V+0gu4Zkfo39HuFegGDJYTBEiK85/2K6KW+Qvde33nd7nriE9ZtP4x24xzpRwZLCIMlxKa1wtXxFTvX4ybo2rE75s412Q8jB8eS/jBYQhgsIcJrhZW5EGLdrXsPK8QcUqoP1hPWZxtXgcbVP85gCWGwhAh/E3qFWAtL9XyvSNVAqZpm8u2gK+ex9DIGSwiDJUR4rfDq7e/craTWBIn9WKmeFKtr1fnEEsJgCWGwhAD7YxH7srvo3g1vGWfP+uCVTywhDJYQBksIcM/7zrWznf1FT/VKSL0LeeV+LL2MwRLCYAmx6Vs6qe/A0HvD6bW2U+9U7q+DfWIJYbCEMFhCBGqsnX2eiL1QlXFWx3Tvc4XucVUZx/1YegGDJYTBEgJ8r7Dye5/6RnL3XGJ/0qk+8t176J57j08sIQyWEAZLiPA8VuUYYq6L3seder+PQPQd9XuFeiiDJYTBEiIwj0V/f6Z7D6n9Ut37mczD7ezPvqdm9YklhMESwmAJEf5eIVHHpPpgPbmHFnHdSf3kPJYeymAJYbCEONAf69R7dk/o3bAap4J4p9LeDXoZgyWEwRICrLGuTn3jZWfPz8mYk3vY2S++zieWEAZLCIMlxIHeDal1w66d7/0RfSi6x6Tu5x6fWEIYLCEMlhDh3g2r3+nUXEuqbqNru+5eK7qv2Ir9sfQyBksIgyXEg/pjXaX2gxM9Rel3D7vndu3pK+ETSwiDJYTBEiL8XmHKpIZY2VmjPO27h/T3iz6McOMc6UcGSwiDJcTNeSy6BuoeQ+zBJ95D7N5D184+Wz+MHBxL+sNgCWGwhAisFRLv/VW+gVM5frIvavXn3f1hq3Em654rk7XLLJ9YQhgsIQyWEOH9WDt7JXT316fuJ7XulvomY2pO0d4NegGDJYTBEgLc807o1jGptT9iDTE195Za93StUC9gsIQwWEK8oMaavHM3qVdWxxPf5CHW+LrroZP7+XCV4fnSRwZLCIMlxKb+WCnEN3lW625P6MtVMVmLvMruwfeJJYTBEsJgCRGosYh3DFd29lufjEN892Zy3e68nfNYeiiDJYTBEuKh/bH0dj6xhDBYQhgsIQyWEAZLCIMlhMESwmAJYbCEMFhCGCwhDJYQBksIgyWEwRLCYAlhsIT4HybO2zx85W0PAAAAAElFTkSuQmCC';
}

View File

@@ -0,0 +1,224 @@
<?php
namespace PragmaRX\Google2FA\Tests;
use PHPUnit\Framework\TestCase;
use PragmaRX\Google2FA\Google2FA;
use PragmaRX\Google2FA\Support\Constants as Google2FAConstants;
class Google2FATest extends TestCase
{
public function setUp()
{
$this->google2fa = new Google2FA();
}
public function testIsInitializable()
{
$this->assertInstanceOf('PragmaRX\Google2FA\Google2FA', $this->google2fa);
}
public function testGeneratesAValidSecretKey()
{
$this->assertEquals(16, strlen($this->google2fa->generateSecretKey()));
$this->assertEquals(32, strlen($this->google2fa->generateSecretKey(32)));
$this->assertStringStartsWith('MFXHI', $this->google2fa->generateSecretKey(59, 'ant'));
$this->assertStringStartsWith('MFXHI', $this->google2fa->generateSecretKey(59, 'ant'));
$this->assertEquals($key = $this->google2fa->generateSecretKey(), preg_replace('/[^'.Google2FAConstants::VALID_FOR_B32.']/', '', $key));
}
/**
* @expectedException \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException
*/
public function testGeneratesASecretKeysCompatibleWithGoogleAuthenticatorOrNot()
{
$this->google2fa->setEnforceGoogleAuthenticatorCompatibility(true)->generateSecretKey(17);
$this->assertEquals(17, strlen($this->google2fa->setEnforceGoogleAuthenticatorCompatibility(false)->generateSecretKey(17)));
}
public function testConvertsInvalidCharsToBase32()
{
$converted = $this->google2fa->generateBase32RandomKey(16, '1234'.chr(250).chr(251).chr(252).chr(253).chr(254).chr(255));
$valid = preg_replace('/[^'.Google2FAConstants::VALID_FOR_B32.']/', '', $converted);
$this->assertEquals($converted, $valid);
}
public function testGetsValidTimestamps()
{
$ts = $this->google2fa->getTimestamp();
$this->assertLessThanOrEqual(PHP_INT_MAX, $ts);
$this->assertGreaterThanOrEqual(~PHP_INT_MAX, $ts);
}
public function testDecodesBase32Strings()
{
$result = chr(0)
.chr(232)
.chr(196)
.chr(187)
.chr(190)
.chr(223)
.chr(26)
.chr(241)
.chr(145)
.chr(86);
$this->assertEquals($result, $this->google2fa->base32Decode(Constants::SECRET));
}
public function testCreatesAOneTimePassword()
{
$this->assertEquals(6, strlen($this->google2fa->getCurrentOtp(Constants::SECRET)));
}
public function testVerifiesKeys()
{
// $ts 26213400 with KEY_REGENERATION 30 seconds is
// timestamp 786402000, which is 1994-12-02 21:00:00 UTC
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '558854', 2, 26213400)); // 26213398
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '981084', 2, 26213400)); // 26213399
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '512396', 2, 26213400)); // 26213400
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '410272', 2, 26213400)); // 26213401
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '239815', 2, 26213400)); // 26213402
$this->assertFalse($this->google2fa->verifyKey(Constants::SECRET, '313366', 2, 26213400)); // 26213403
$this->assertFalse($this->google2fa->verifyKey(Constants::SECRET, '093183', 2, 26213400)); // 26213397
}
public function testVerifiesKeysNewer()
{
$this->assertFalse($this->google2fa->verifyKeyNewer(Constants::SECRET, '512396', 26213401, 2, 26213400));
$this->assertFalse($this->google2fa->verifyKeyNewer(Constants::SECRET, '410272', 26213401, 2, 26213400));
$this->assertEquals(26213402, $this->google2fa->verifyKeyNewer(Constants::SECRET, '239815', 26213401, 2, 26213400));
$this->assertFalse($this->google2fa->verifyKeyNewer(Constants::SECRET, '313366', 26213401, 2, 26213400));
$this->assertEquals(26213400, $this->google2fa->verifyKeyNewer(Constants::SECRET, '512396', null, 2, 26213400));
$this->assertEquals(26213401, $this->google2fa->verifyKeyNewer(Constants::SECRET, '410272', null, 2, 26213400));
$this->assertEquals(26213402, $this->google2fa->verifyKeyNewer(Constants::SECRET, '239815', null, 2, 26213400));
$this->assertFalse($this->google2fa->verifyKeyNewer(Constants::SECRET, '313366', null, 2, 26213400));
}
public function testRemovesInvalidCharsFromSecret()
{
$this->assertEquals(Constants::SECRET, $this->google2fa->removeInvalidChars(Constants::SECRET.'!1-@@@'));
}
public function testCreatesAQrCode()
{
$this->assertEquals(Constants::URL, $this->google2fa->setAllowInsecureCallToGoogleApis(true)->getQRCodeGoogleUrl('PragmaRX', 'acr+pragmarx@antoniocarlosribeiro.com', Constants::SECRET));
}
/**
* @expectedException \PragmaRX\Google2FA\Exceptions\InsecureCallException
*/
public function testGetExceptionWhenUsingGoogleApis()
{
$this->assertEquals(Constants::URL, $this->google2fa->getQRCodeGoogleUrl('PragmaRX', 'acr+pragmarx@antoniocarlosribeiro.com', Constants::SECRET));
}
public function testConvertsToBase32()
{
$this->assertEquals('KBZGCZ3NMFJFQ', $this->google2fa->toBase32('PragmaRX'));
}
public function testSetsTheWindow()
{
$this->google2fa->setWindow(6);
$this->assertEquals(6, $this->google2fa->getWindow());
$this->assertEquals(1, $this->google2fa->getWindow(1));
$this->google2fa->setWindow(0);
$this->assertFalse($this->google2fa->verifyKey(Constants::SECRET, '558854', null, 26213400));
$this->google2fa->setWindow(2);
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '558854', null, 26213400));
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '558854', null, 26213399));
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '558854', null, 26213398));
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '558854', null, 26213396));
$this->assertFalse($this->google2fa->verifyKey(Constants::SECRET, '558854', null, 26213395));
}
public function testSetsTheSecret()
{
$this->assertFalse($this->google2fa->verify('558854', Constants::WRONG_SECRET));
$this->google2fa->setWindow(2);
$this->assertTrue($this->google2fa->verify('558854', Constants::SECRET, null, 26213400));
$this->google2fa->setSecret(Constants::SECRET);
$this->assertTrue($this->google2fa->verify('558854', null, null, 26213400));
}
public function testGetsKeyRegeneration()
{
$this->google2fa->setKeyRegeneration(11);
$this->assertEquals(11, $this->google2fa->getKeyRegeneration());
}
public function testGetsOtpLength()
{
$this->google2fa->setOneTimePasswordLength(7);
$this->assertEquals(7, $this->google2fa->getOneTimePasswordLength());
}
public function testGeneratesPasswordsInManyDifferentSizes()
{
$this->google2fa->setWindow(2);
$this->google2fa->setOneTimePasswordLength(6);
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '558854', null, 26213400));
$this->google2fa->setOneTimePasswordLength(7);
$this->assertTrue($this->google2fa->verifyKey(Constants::SECRET, '8981084', null, 26213400));
}
/**
* @expectedException \PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException
*/
public function testShortSecretKey()
{
$this->google2fa->setEnforceGoogleAuthenticatorCompatibility(false);
$this->google2fa->verifyKey(Constants::SHORT_SECRET, '558854', null, 26213400);
}
/**
* @expectedException \PragmaRX\Google2FA\Exceptions\InvalidCharactersException
*/
public function testValidateKey()
{
$this->assertTrue(is_numeric($this->google2fa->getCurrentOtp(Constants::SECRET)));
$this->google2fa->setEnforceGoogleAuthenticatorCompatibility(false);
$this->google2fa->getCurrentOtp(Constants::INVALID_SECRET);
}
public function testQrcodeInline()
{
$this->assertEquals(
phpversion() >= '7.2' ? Constants::QRCODEPHPABOVE72 : Constants::QRCODEPHPBELOW72,
$this->google2fa->getQRCodeInline('PragmaRX', 'acr+pragmarx@antoniocarlosribeiro.com', Constants::SECRET)
);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
|--------------------------------------------------------------------------
| Register The Composer Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/
require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Set The Default Timezone
|--------------------------------------------------------------------------
|
| Here we will set the default timezone for PHP. PHP is notoriously mean
| if the timezone is not explicitly set. This will be used by each of
| the PHP date and date-time functions throughout the application.
|
*/
date_default_timezone_set('UTC');
function d($args)
{
foreach ($args as $arg) {
var_dump($arg);
}
}
function dd()
{
d(func_get_args());
die;
}

View File

@@ -0,0 +1,2 @@
# Google2FA