diff --git a/CHANGELOG.md b/CHANGELOG.md
index 08a32cf..936cd57 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+# 3.0.6
+## 02/11/2020
+
+1. [](#new)
+ * Pass phpstan level 1 tests
+ * Updated 2FA library to v1.7.0
+* [](#improved)
+ * Added some debugging messages (turned off by default)
+
# 3.0.5
## 01/02/2020
diff --git a/blueprints.yaml b/blueprints.yaml
index b0aa89d..89cc8f3 100644
--- a/blueprints.yaml
+++ b/blueprints.yaml
@@ -1,5 +1,5 @@
name: Login
-version: 3.0.5
+version: 3.0.6
testing: false
description: Enables user authentication and login screen.
icon: sign-in
diff --git a/classes/Controller.php b/classes/Controller.php
index c982a08..8824f4f 100644
--- a/classes/Controller.php
+++ b/classes/Controller.php
@@ -56,12 +56,6 @@ class Controller
*/
protected $prefix = 'task';
- /**
- * @var RememberMe\RememberMe
- * @deprecated 2.0 Use $grav['login']->rememberMe() instead
- */
- protected $rememberMe;
-
/**
* @var Login
*/
@@ -78,8 +72,6 @@ public function __construct(Grav $grav, $action, $post = null)
$this->action = $action;
$this->login = $this->grav['login'];
$this->post = $post ? $this->getPost($post) : [];
-
- $this->rememberMe();
}
/**
@@ -554,9 +546,7 @@ protected function jsonDecode(array $data)
*/
public function rememberMe($var = null)
{
- $this->rememberMe = $this->login->rememberMe($var);
-
- return $this->rememberMe;
+ return $this->login->rememberMe($var);
}
/**
diff --git a/classes/Events/UserLoginEvent.php b/classes/Events/UserLoginEvent.php
index 8b16112..e5a75e0 100644
--- a/classes/Events/UserLoginEvent.php
+++ b/classes/Events/UserLoginEvent.php
@@ -13,6 +13,7 @@
use Grav\Common\Session;
use Grav\Common\User\Interfaces\UserCollectionInterface;
use Grav\Common\User\Interfaces\UserInterface;
+use Grav\Plugin\Login\Login;
use RocketTheme\Toolbox\Event\Event;
/**
@@ -92,7 +93,17 @@ public function __construct(array $items = [])
if (!$this->offsetExists('user')) {
/** @var UserCollectionInterface $users */
$users = Grav::instance()['accounts'];
- $this->offsetSet('user', $users->load($this['credentials']['username']));
+ $user = $users->load($this['credentials']['username']);
+ $this->offsetSet('user', $user);
+
+ if (Login::DEBUG) {
+ if ($user->exists()) {
+ Login::addDebugMessage('Login user:', $user);
+ } else {
+ Login::addDebugMessage("Login: user '{$this['credentials']['username']}' not found");
+ }
+ }
+
}
}
@@ -349,4 +360,12 @@ public function __unset($offset)
{
$this->offsetUnset($offset);
}
+
+ /**
+ * @return array
+ */
+ public function __debugInfo(): array
+ {
+ return get_object_vars($this);
+ }
}
diff --git a/classes/Login.php b/classes/Login.php
index c8f90ec..763f70e 100755
--- a/classes/Login.php
+++ b/classes/Login.php
@@ -12,6 +12,7 @@
use Birke\Rememberme\Cookie;
use Grav\Common\Config\Config;
use Grav\Common\Data\Data;
+use Grav\Common\Debugger;
use Grav\Common\Grav;
use Grav\Common\Language\Language;
use Grav\Common\Page\Interfaces\PageInterface;
@@ -32,6 +33,8 @@
*/
class Login
{
+ public const DEBUG = 1;
+
/** @var Grav */
protected $grav;
@@ -73,6 +76,17 @@ public function __construct(Grav $grav)
$this->uri = $this->grav['uri'];
}
+ /**
+ * @param string $message
+ * @param array $data
+ */
+ public static function addDebugMessage(string $message, $data = [])
+ {
+ /** @var Debugger $debugger */
+ $debugger = Grav::instance()['debugger'];
+ $debugger->addMessage($message, 'debug', $data);
+ }
+
/**
* Login user.
*
@@ -95,6 +109,7 @@ public function login(array $credentials, array $options = [], array $extra = []
$grav->fireEvent('onUserLoginAuthenticate', $event);
if ($event->isSuccess()) {
+ static::DEBUG && static::addDebugMessage('Login onUserLoginAuthenticate: success', $event);
// Make sure that event didn't mess up with the user authorization.
$user = $event->getUser();
@@ -107,6 +122,8 @@ public function login(array $credentials, array $options = [], array $extra = []
}
if ($event->isSuccess()) {
+ static::DEBUG && static::addDebugMessage('Login onUserLoginAuthorize: success', $event);
+
// User has been logged in, let plugins know.
$event = new UserLoginEvent($event->toArray());
$grav->fireEvent('onUserLogin', $event);
@@ -117,6 +134,8 @@ public function login(array $credentials, array $options = [], array $extra = []
$user->authorized = !$event->isDelayed();
} else {
+ static::DEBUG && static::addDebugMessage('Login failed', $event);
+
// Allow plugins to log errors or do other tasks on failure.
$event = new UserLoginEvent($event->toArray());
$grav->fireEvent('onUserLoginFailure', $event);
@@ -650,5 +669,4 @@ public function getProviderLoginTemplates()
{
return $this->provider_login_templates;
}
-
}
diff --git a/composer.json b/composer.json
index c670f50..3dc8c13 100644
--- a/composer.json
+++ b/composer.json
@@ -34,8 +34,12 @@
},
"autoload": {
"psr-4": {
- "Grav\\Plugin\\Login\\": "classes/"
- }
+ "Grav\\Plugin\\Login\\": "classes/",
+ "Grav\\Plugin\\Console\\": "cli/"
+ },
+ "classmap": [
+ "login.php"
+ ]
},
"config": {
"platform": {
diff --git a/composer.lock b/composer.lock
index 453b273..591e5ca 100644
--- a/composer.lock
+++ b/composer.lock
@@ -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": "bb17626cbf2be970add218a7cab0535f",
+ "content-hash": "28a285533fbaa23e98ab6350b8207efd",
"packages": [
{
"name": "bacon/bacon-qr-code",
@@ -147,20 +147,20 @@
},
{
"name": "robthree/twofactorauth",
- "version": "1.6.1",
+ "version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/RobThree/TwoFactorAuth.git",
- "reference": "a77e7d822343bb88112baef808839cfae7bc5abb"
+ "reference": "37983bf675c5baca09d19d6705170489d0df0002"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/a77e7d822343bb88112baef808839cfae7bc5abb",
- "reference": "a77e7d822343bb88112baef808839cfae7bc5abb",
+ "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/37983bf675c5baca09d19d6705170489d0df0002",
+ "reference": "37983bf675c5baca09d19d6705170489d0df0002",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": ">=5.6.0"
},
"require-dev": {
"phpunit/phpunit": "@stable"
@@ -194,7 +194,7 @@
"php",
"tfa"
],
- "time": "2017-11-06T17:55:56+00:00"
+ "time": "2020-01-02T19:56:46+00:00"
}
],
"packages-dev": [],
@@ -204,7 +204,11 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=5.5.9"
+ "php": ">=7.1.3",
+ "ext-json": "*"
},
- "platform-dev": []
+ "platform-dev": [],
+ "platform-overrides": {
+ "php": "7.1.3"
+ }
}
diff --git a/login.php b/login.php
index 6947670..bf51bd9 100755
--- a/login.php
+++ b/login.php
@@ -206,7 +206,7 @@ public function pageVisibility(Event $e)
foreach ($pages->instances() as $page) {
$header = $page->header();
- if (isset($header) && isset($header->access) && isset($header->login['visibility_requires_access']) && $header->login['visibility_requires_access'] === true) {
+ if ($header && isset($header->access) && isset($header->login['visibility_requires_access']) && $header->login['visibility_requires_access'] === true) {
$config = $this->mergeConfig($page);
$access = $this->login->isUserAuthorizedForPage($user, $page, $config);
if ($access === false) {
@@ -671,7 +671,6 @@ private function processUserRegistration($form, Event $event)
}
$form->validate();
- $form->filter();
/** @var Data $form_data */
$form_data = $form->getData();
@@ -827,7 +826,6 @@ private function processUserProfile($form, Event $event)
$language = $this->grav['language'];
$form->validate();
- $form->filter();
/** @var Data $form_data */
$form_data = $form->getData();
diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php
index 7a91153..b56d752 100644
--- a/vendor/composer/autoload_classmap.php
+++ b/vendor/composer/autoload_classmap.php
@@ -6,4 +6,5 @@
$baseDir = dirname($vendorDir);
return array(
+ 'Grav\\Plugin\\LoginPlugin' => $baseDir . '/login.php',
);
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
index 461a84b..a43c8d6 100644
--- a/vendor/composer/autoload_psr4.php
+++ b/vendor/composer/autoload_psr4.php
@@ -8,5 +8,6 @@
return array(
'RobThree\\Auth\\' => array($vendorDir . '/robthree/twofactorauth/lib'),
'Grav\\Plugin\\Login\\' => array($baseDir . '/classes'),
+ 'Grav\\Plugin\\Console\\' => array($baseDir . '/cli'),
'Birke\\' => array($vendorDir . '/birke/rememberme/src'),
);
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
index b9badf9..d54719c 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -18,6 +18,7 @@ class ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366
'G' =>
array (
'Grav\\Plugin\\Login\\' => 18,
+ 'Grav\\Plugin\\Console\\' => 20,
),
'B' =>
array (
@@ -34,6 +35,10 @@ class ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366
array (
0 => __DIR__ . '/../..' . '/classes',
),
+ 'Grav\\Plugin\\Console\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/cli',
+ ),
'Birke\\' =>
array (
0 => __DIR__ . '/..' . '/birke/rememberme/src',
@@ -50,12 +55,17 @@ class ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366
),
);
+ public static $classMap = array (
+ 'Grav\\Plugin\\LoginPlugin' => __DIR__ . '/../..' . '/login.php',
+ );
+
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$prefixesPsr0;
+ $loader->classMap = ComposerStaticIniteed5e5cf0aa1e2139f2db7445511e366::$classMap;
}, null, ClassLoader::class);
}
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index caddc63..209919f 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -146,26 +146,26 @@
},
{
"name": "robthree/twofactorauth",
- "version": "1.6.1",
- "version_normalized": "1.6.1.0",
+ "version": "1.7.0",
+ "version_normalized": "1.7.0.0",
"source": {
"type": "git",
"url": "https://github.com/RobThree/TwoFactorAuth.git",
- "reference": "a77e7d822343bb88112baef808839cfae7bc5abb"
+ "reference": "37983bf675c5baca09d19d6705170489d0df0002"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/a77e7d822343bb88112baef808839cfae7bc5abb",
- "reference": "a77e7d822343bb88112baef808839cfae7bc5abb",
+ "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/37983bf675c5baca09d19d6705170489d0df0002",
+ "reference": "37983bf675c5baca09d19d6705170489d0df0002",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "php": ">=5.6.0"
},
"require-dev": {
"phpunit/phpunit": "@stable"
},
- "time": "2017-11-06T17:55:56+00:00",
+ "time": "2020-01-02T19:56:46+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
diff --git a/vendor/robthree/twofactorauth/.travis.yml b/vendor/robthree/twofactorauth/.travis.yml
index 204dc63..fdc6ff5 100644
--- a/vendor/robthree/twofactorauth/.travis.yml
+++ b/vendor/robthree/twofactorauth/.travis.yml
@@ -1,18 +1,15 @@
language: php
-dist: trusty
-matrix:
- include:
- - php: 5.3
- dist: precise
-
php:
- - 5.4
- - 5.5
- 5.6
- 7.0
- 7.1
- - hhvm
+ - 7.2
+ - 7.3
+ - 7.4
+
+before_script:
+ - composer install
script:
- - if [[ "$TRAVIS_PHP_VERSION" == '5.6' ]]; then phpunit --coverage-text tests ; fi
\ No newline at end of file
+ - vendor/bin/phpunit --coverage-text tests
\ No newline at end of file
diff --git a/vendor/robthree/twofactorauth/README.md b/vendor/robthree/twofactorauth/README.md
index ba6cfea..3574ae9 100644
--- a/vendor/robthree/twofactorauth/README.md
+++ b/vendor/robthree/twofactorauth/README.md
@@ -1,6 +1,6 @@
# ![Logo](https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/logo.png) PHP library for Two Factor Authentication
-[![Build status](https://img.shields.io/travis/RobThree/TwoFactorAuth.svg?style=flat-square)](https://travis-ci.org/RobThree/TwoFactorAuth/) [![Latest Stable Version](https://img.shields.io/packagist/v/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![License](https://img.shields.io/packagist/l/robthree/twofactorauth.svg?style=flat-square)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![HHVM Status](https://img.shields.io/hhvm/RobThree/TwoFactorAuth.svg?style=flat-square)](http://hhvm.h4cc.de/package/robthree/twofactorauth) [![Code Climate](https://img.shields.io/codeclimate/github/RobThree/TwoFactorAuth.svg?style=flat-square)](https://codeclimate.com/github/RobThree/TwoFactorAuth) [![PayPal donate button](http://img.shields.io/badge/paypal-donate-orange.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MB5M2SQLP636 "Keep me off the streets")
+[![Build status](https://img.shields.io/travis/RobThree/TwoFactorAuth.svg?style=flat-square)](https://travis-ci.org/RobThree/TwoFactorAuth/) [![Latest Stable Version](https://img.shields.io/packagist/v/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![License](https://img.shields.io/packagist/l/robthree/twofactorauth.svg?style=flat-square)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![Code Climate](https://img.shields.io/codeclimate/github/RobThree/TwoFactorAuth.svg?style=flat-square)](https://codeclimate.com/github/RobThree/TwoFactorAuth) [![PayPal donate button](http://img.shields.io/badge/paypal-donate-orange.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MB5M2SQLP636 "Keep me off the streets")
PHP library for [two-factor (or multi-factor) authentication](http://en.wikipedia.org/wiki/Multi-factor_authentication) using [TOTP](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) and [QR-codes](http://en.wikipedia.org/wiki/QR_code). Inspired by, based on but most importantly an *improvement* on '[PHPGangsta/GoogleAuthenticator](https://github.com/PHPGangsta/GoogleAuthenticator)'. There's a [.Net implementation](https://github.com/RobThree/TwoFactorAuth.Net) of this library as well.
@@ -10,8 +10,8 @@ PHP library for [two-factor (or multi-factor) authentication](http://en.wikipedi
## Requirements
-* Tested on PHP 5.3, 5.4, 5.5 and 5.6, 7.0, 7.1 and HHVM
-* [cURL](http://php.net/manual/en/book.curl.php) when using the provided `GoogleQRCodeProvider` (default), `QRServerProvider` or `QRicketProvider` but you can also provide your own QR-code provider.
+* Tested on PHP 5.6 up to 7.4
+* [cURL](http://php.net/manual/en/book.curl.php) when using the provided `ImageChartsQRCodeProvider` (default), `QRServerProvider` or `QRicketProvider` but you can also provide your own QR-code provider.
* [random_bytes()](http://php.net/manual/en/function.random-bytes.php), [MCrypt](http://php.net/manual/en/book.mcrypt.php), [OpenSSL](http://php.net/manual/en/book.openssl.php) or [Hash](http://php.net/manual/en/book.hash.php) depending on which built-in RNG you use (TwoFactorAuth will try to 'autodetect' and use the best available); however: feel free to provide your own (CS)RNG.
## Installation
@@ -33,9 +33,9 @@ Here are some code snippets that should help you get started...
$tfa = new RobThree\Auth\TwoFactorAuth('My Company');
````
-The TwoFactorAuth class constructor accepts 7 parameters (all optional):
+The TwoFactorAuth class constructor accepts 7 arguments (all optional):
-Parameter | Default value | Use
+Argument | Default value | Use
------------------|---------------|--------------------------------------------------
`$issuer` | `null` | Will be displayed in the app as issuer name
`$digits` | `6` | The number of digits the resulting codes will be
@@ -45,7 +45,7 @@ Parameter | Default value | Use
`$rngprovider` | `null` | Random Number Generator provider (more on this later)
`$timeprovider` | `null` | Time provider (more on this later)
-These parameters are all '`write once`'; the class will, for it's lifetime, use these values when generating / calculating codes. The number of digits, the period and algorithm are all set to values Google's Authticator app uses (and supports). You may specify `8` digits, a period of `45` seconds and the `sha256` algorithm but the authenticator app (be it Google's implementation, Authy or any other app) may or may not support these values. Your mileage may vary; keep it on the safe side if you don't control which app your audience uses.
+These arguments are all '`write once`'; the class will, for it's lifetime, use these values when generating / calculating codes. The number of digits, the period and algorithm are all set to values Google's Authticator app uses (and supports). You may specify `8` digits, a period of `45` seconds and the `sha256` algorithm but the authenticator app (be it Google's implementation, Authy or any other app) may or may not support these values. Your mileage may vary; keep it on the safe side if you don't control which app your audience uses.
### Step 1: Set up secret shared key
@@ -64,11 +64,11 @@ The `createSecret()` method accepts two arguments: `$bits` (default: `80`) and `
Another, more user-friendly, way to get the shared secret into the app is to generate a [QR-code](http://en.wikipedia.org/wiki/QR_code) which can be scanned by the app. To generate these QR codes you can use any one of the built-in `QRProvider` classes:
-1. `GoogleQRCodeProvider` (default)
+1. `ImageChartsQRCodeProvider` (default)
2. `QRServerProvider`
3. `QRicketProvider`
-...or implement your own provider. To implement your own provider all you need to do is implement the `IQRCodeProvider` interface. You can use the built-in providers mentioned before to serve as an example or read the next chapter in this file. The built-in classes all use a 3rd (e.g. external) party (Google, QRServer and QRicket) for the hard work of generating QR-codes (note: each of these services might at some point not be available or impose limitations to the number of codes generated per day, hour etc.). You could, however, easily use a project like [PHP QR Code](http://phpqrcode.sourceforge.net/) (or one of the [many others](https://packagist.org/search/?q=qr)) to generate your QR-codes without depending on external sources. Later on we'll [demonstrate](#qr-code-providers) how to do this.
+...or implement your own provider. To implement your own provider all you need to do is implement the `IQRCodeProvider` interface. You can use the built-in providers mentioned before to serve as an example or read the next chapter in this file. The built-in classes all use a 3rd (e.g. external) party (Image-charts, QRServer and QRicket) for the hard work of generating QR-codes (note: each of these services might at some point not be available or impose limitations to the number of codes generated per day, hour etc.). You could, however, easily use a project like [PHP QR Code](http://phpqrcode.sourceforge.net/) (or one of the [many others](https://packagist.org/search/?q=qr)) to generate your QR-codes without depending on external sources. Later on we'll [demonstrate](#qr-code-providers) how to do this.
The built-in providers all have some provider-specific 'tweaks' you can 'apply'. Some provide support for different colors, others may let you specify the desired image-format etc. What they all have in common is that they return a QR-code as binary blob which, in turn, will be turned into a [data URI](http://en.wikipedia.org/wiki/Data_URI_scheme) by the `TwoFactorAuth` class. This makes it easy for you to display the image without requiring extra 'roundtrips' from browser to server and vice versa.
@@ -89,9 +89,11 @@ When the shared secret is added to the app, the app will be ready to start gener
$result = $tfa->verifyCode($_SESSION['secret'], $_POST['verification']);
````
-`verifyCode()` will return either `true` (the code was valid) or `false` (the code was invalid; no points for you!). You may need to store `$secret` in a `$_SESSION` or other persistent storage between requests. The `verifyCode()` accepts, aside from `$secret` and `$code`, two more parameters. The first being `$discrepancy`. Since TOTP codes are based on time("slices") it is very important that the server (but also client) have a correct date/time. But because the two *may* differ a bit we usually allow a certain amount of leeway. Because generated codes are valid for a specific period (remember the `$period` parameter in the `TwoFactorAuth`'s constructor?) we usually check the period directly before and the period directly after the current time when validating codes. So when the current time is `14:34:21`, which results in a 'current timeslice' of `14:34:00` to `14:34:30` we also calculate/verify the codes for `14:33:30` to `14:34:00` and for `14:34:30` to `14:35:00`. This gives us a 'window' of `14:33:30` to `14:35:00`. The `$discrepancy` parameter specifies how many periods (or: timeslices) we check in either direction of the current time. The default `$discrepancy` of `1` results in (max.) 3 period checks: -1, current and +1 period. A `$discrepancy` of `4` would result in a larger window (or: bigger time difference between client and server) of -4, -3, -2, -1, current, +1, +2, +3 and +4 periods.
+`verifyCode()` will return either `true` (the code was valid) or `false` (the code was invalid; no points for you!). You may need to store `$secret` in a `$_SESSION` or other persistent storage between requests. The `verifyCode()` accepts, aside from `$secret` and `$code`, three more arguments. The first being `$discrepancy`. Since TOTP codes are based on time("slices") it is very important that the server (but also client) have a correct date/time. But because the two *may* differ a bit we usually allow a certain amount of leeway. Because generated codes are valid for a specific period (remember the `$period` argument in the `TwoFactorAuth`'s constructor?) we usually check the period directly before and the period directly after the current time when validating codes. So when the current time is `14:34:21`, which results in a 'current timeslice' of `14:34:00` to `14:34:30` we also calculate/verify the codes for `14:33:30` to `14:34:00` and for `14:34:30` to `14:35:00`. This gives us a 'window' of `14:33:30` to `14:35:00`. The `$discrepancy` argument specifies how many periods (or: timeslices) we check in either direction of the current time. The default `$discrepancy` of `1` results in (max.) 3 period checks: -1, current and +1 period. A `$discrepancy` of `4` would result in a larger window (or: bigger time difference between client and server) of -4, -3, -2, -1, current, +1, +2, +3 and +4 periods.
-The second parameter `$time` allows you to check a code for a specific point in time. This parameter has no real practical use but can be handy for unittesting etc. The default value, `null`, means: use the current time.
+The second, `$time`, allows you to check a code for a specific point in time. This argument has no real practical use but can be handy for unittesting etc. The default value, `null`, means: use the current time.
+
+The third, `$timeslice`, is an out-argument; the value returned in `$timeslice` is the value of the timeslice that matched the code (if any). This value will be 0 when the code doesn't match and non-zero when the code matches. This value can be stored with the user and can be used to prevent replay-attacks. All you need to do is, on successful login, make sure `$timeslice` is greater than the previously stored timeslice.
### Step 3: Store `$secret` with user and we're done!
@@ -117,9 +119,9 @@ public function verifyCode($secret, $code, $discrepancy = 1, $time = null): bool
### QR-code providers
-As mentioned before, this library comes with three 'built-in' QR-code providers. This chapter will touch the subject a bit but most of it should be self-explanatory. The `TwoFactorAuth`-class accepts a `$qrcodeprovider` parameter which lets you specify a built-in or custom QR-code provider. All three built-in providers do a simple HTTP request to retrieve an image using cURL and implement the [`IQRCodeProvider`](lib/Providers/Qr/IQRCodeProvider.php) interface which is all you need to implement to write your own QR-code provider.
+As mentioned before, this library comes with three 'built-in' QR-code providers. This chapter will touch the subject a bit but most of it should be self-explanatory. The `TwoFactorAuth`-class accepts a `$qrcodeprovider` argument which lets you specify a built-in or custom QR-code provider. All three built-in providers do a simple HTTP request to retrieve an image using cURL and implement the [`IQRCodeProvider`](lib/Providers/Qr/IQRCodeProvider.php) interface which is all you need to implement to write your own QR-code provider.
-The default provider is the [`GoogleQRCodeProvider`](lib/Providers/Qr/GoogleQRCodeProvider.php) which uses the [Google Chart Tools](https://developers.google.com/chart/infographics/docs/qr_codes) to render QR-codes. Then we have the [`QRServerProvider`](lib/Providers/Qr/QRServerProvider.php) which uses the [goqr.me API](http://goqr.me/api/doc/create-qr-code/) and finally we have the [`QRicketProvider`](lib/Providers/Qr/QRicketProvider.php) which uses the [QRickit API](http://qrickit.com/qrickit_apps/qrickit_api.php). All three inherit from a common (abstract) baseclass named [`BaseHTTPQRCodeProvider`](lib/Providers/Qr/BaseHTTPQRCodeProvider.php) because all three share the same functionality: retrieve an image from a 3rd party over HTTP. All three classes have constructors that allow you to tweak some settings and most, if not all, arguments should speak for themselves. If you're not sure which values are supported, click the links in this paragraph for documentation on the API's that are utilized by these classes.
+The default provider is the [`ImageChartsQRCodeProvider`](lib/Providers/Qr/ImageChartsQRCodeProvider.php) which uses the [image-charts.com replacement for Google Image Charts](https://image-charts.com) to render QR-codes. Then we have the [`QRServerProvider`](lib/Providers/Qr/QRServerProvider.php) which uses the [goqr.me API](http://goqr.me/api/doc/create-qr-code/) and finally we have the [`QRicketProvider`](lib/Providers/Qr/QRicketProvider.php) which uses the [QRickit API](http://qrickit.com/qrickit_apps/qrickit_api.php). All three inherit from a common (abstract) baseclass named [`BaseHTTPQRCodeProvider`](lib/Providers/Qr/BaseHTTPQRCodeProvider.php) because all three share the same functionality: retrieve an image from a 3rd party over HTTP. All three classes have constructors that allow you to tweak some settings and most, if not all, arguments should speak for themselves. If you're not sure which values are supported, click the links in this paragraph for documentation on the API's that are utilized by these classes.
If you don't like any of the built-in classes because you don't want to rely on external resources for example or because you're paranoid about sending the TOTP secret to these 3rd parties (which is useless to them since they miss *at least one* other factor in the [MFA process](http://en.wikipedia.org/wiki/Multi-factor_authentication)), feel tree to implement your own. The `IQRCodeProvider` interface couldn't be any simpler. All you need to do is implement 2 methods:
@@ -132,7 +134,7 @@ The `getMimeType()` method should return the [MIME type](http://en.wikipedia.org
`otpauth://totp/LABEL:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=ISSUER`
-All you need to do is return the QR-code as binary image data and you're done. All parts of the `$qrtext` have been escaped for you (but note: you *may* need to escape the entire `$qrtext` just once more when passing the data to another server as GET-parameter).
+All you need to do is return the QR-code as binary image data and you're done. All parts of the `$qrtext` have been escaped for you (but note: you *may* need to escape the entire `$qrtext` just once more when passing the data to another server as GET-argument).
Let's see if we can use [PHP QR Code](http://phpqrcode.sourceforge.net/) to implement our own, custom, no-3rd-parties-allowed-here, provider. We start with downloading the [required (single) file](https://github.com/t0k4rt/phpqrcode/blob/master/phpqrcode.php) and putting it in the directory where `TwoFactorAuth.php` is located as well. Now let's implement the provider: create another file named `myprovider.php` in the `Providers\Qr` directory and paste in this content:
@@ -176,15 +178,15 @@ Voilà. Couldn't make it any simpler.
This library also comes with three 'built-in' RNG providers ([Random Number Generator](https://en.wikipedia.org/wiki/Random_number_generation)). The RNG provider generates a number of random bytes and returns these bytes as a string. These values are then used to create the secret. By default (no RNG provider specified) TwoFactorAuth will try to determine the best available RNG provider to use. It will, by default, try to use the [`CSRNGProvider`](lib/Providers/Rng/CSRNGProvider.php) for PHP7+ or the [`MCryptRNGProvider`](lib/Providers/Rng/MCryptRNGProvider.php); if this is not available/supported for any reason it will try to use the [`OpenSSLRNGProvider`](lib/Providers/Rng/OpenSSLRNGProvider.php) and if that is also not available/supported it will try to use the final RNG provider: [`HashRNGProvider`](lib/Providers/Rng/HashRNGProvider.php). Each of these providers use their own method of generating a random sequence of bytes. The first three (`CSRNGProvider`, `OpenSSLRNGProvider` and `MCryptRNGProvider`) return a [cryptographically secure](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) sequence of random bytes whereas the `HashRNGProvider` returns a **non-cryptographically secure** sequence.
-You can easily implement your own `RNGProvider` by simply implementing the `IRNGProvider` interface. Each of the 'built-in' RNG providers have some constructor parameters that allow you to 'tweak' some of the settings to use when creating the random bytes such as which source to use (`MCryptRNGProvider`) or which hashing algorithm (`HashRNGProvider`). I encourage you to have a look at some of the ['built-in' RNG providers](lib/Providers/Rng) for details and the [`IRNGProvider` interface](lib/Providers/Rng/IRNGProvider.php).
+You can easily implement your own `RNGProvider` by simply implementing the `IRNGProvider` interface. Each of the 'built-in' RNG providers have some constructor arguments that allow you to 'tweak' some of the settings to use when creating the random bytes such as which source to use (`MCryptRNGProvider`) or which hashing algorithm (`HashRNGProvider`). I encourage you to have a look at some of the ['built-in' RNG providers](lib/Providers/Rng) for details and the [`IRNGProvider` interface](lib/Providers/Rng/IRNGProvider.php).
### Time providers
-Another set of providers in this library are the Time Providers; this library provides three 'built-in' ones. The default Time Provider used is the [`LocalMachineTimeProvider`](lib/Providers/Time/LocalMachineTimeProvider.php); this provider simply returns the output of `Time()` and is *highly recommended* as default provider. The [`HttpTimeProvider`](lib/Providers/Time/HttpTimeProvider.php) executes a `HEAD` request against a given webserver (default: google.com) and tries to extract the `Date:`-HTTP header and returns it's date. Other url's/domains can be used by specifying the url in the constructor. The final Time Provider is the [`ConvertUnixTimeDotComTimeProvider`](lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php) which does a HTTP request to `convert-unix-time.com/api` and decodes the `JSON` result to retrieve the time.
+Another set of providers in this library are the Time Providers; this library provides three 'built-in' ones. The default Time Provider used is the [`LocalMachineTimeProvider`](lib/Providers/Time/LocalMachineTimeProvider.php); this provider simply returns the output of `Time()` and is *highly recommended* as default provider. The [`HttpTimeProvider`](lib/Providers/Time/HttpTimeProvider.php) executes a `HEAD` request against a given webserver (default: google.com) and tries to extract the `Date:`-HTTP header and returns it's date. Other url's/domains can be used by specifying the url in the constructor. The final Time Provider is the [`NTPTimeProvider`](lib/Providers/Time/NTPTimeProvider.php) which does an NTP request to a specified NTP server.
You can easily implement your own `TimeProvider` by simply implementing the `ITimeProvider` interface.
-As to *why* these Time Providers are implemented: it allows the TwoFactorAuth library to ensure the hosts time is correct (or rather: within a margin). You can use the `ensureCorrectTime()` method to ensure the hosts time is correct. By default this method will compare the hosts time (returned by calling `time()` on the `LocalMachineTimeProvider`) to Google's and convert-unix-time.com's current time. You can pass an array of `ITimeProvider`s and specify the `leniency` (second argument) allowed (default: 5 seconds). The method will throw when the TwoFactorAuth's timeprovider (which can be any `ITimeProvider`, see constructor) differs more than the given amount of seconds from any of the given `ITimeProviders`. We advise to call this method sparingly when relying on 3rd parties (which both the `HttpTimeProvider` and `ConvertUnixTimeDotComTimeProvider` do) or, if you need to ensure time is correct on a (very) regular basis to implement an `ITimeProvider` that is more efficient than the 'built-in' ones (like use a GPS signal). The `ensureCorrectTime()` method is mostly to be used to make sure the server is configured correctly.
+As to *why* these Time Providers are implemented: it allows the TwoFactorAuth library to ensure the hosts time is correct (or rather: within a margin). You can use the `ensureCorrectTime()` method to ensure the hosts time is correct. By default this method will compare the hosts time (returned by calling `time()` on the `LocalMachineTimeProvider`) to the default `NTPTimeProvider` and `HttpTimeProvider`. You can pass an array of `ITimeProvider`s to change this and specify the `leniency` (second argument) allowed (default: 5 seconds). The method will throw when the TwoFactorAuth's timeprovider (which can be any `ITimeProvider`, see constructor) differs more than the given amount of seconds from any of the given `ITimeProviders`. We advise to call this method sparingly when relying on 3rd parties (which both the `HttpTimeProvider` and `NTPTimeProvider` do) or, if you need to ensure time is correct on a (very) regular basis to implement an `ITimeProvider` that is more efficient than the 'built-in' ones (like use a GPS signal). The `ensureCorrectTime()` method is mostly to be used to make sure the server is configured correctly.
## Integrations
diff --git a/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj b/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj
index 7fa2a58..b7e00d6 100644
--- a/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj
+++ b/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj
@@ -27,7 +27,7 @@
-
+
@@ -38,10 +38,10 @@
-
+
@@ -65,5 +65,6 @@
+
\ No newline at end of file
diff --git a/vendor/robthree/twofactorauth/composer.json b/vendor/robthree/twofactorauth/composer.json
index 1ea66ab..50f8b86 100644
--- a/vendor/robthree/twofactorauth/composer.json
+++ b/vendor/robthree/twofactorauth/composer.json
@@ -1,7 +1,7 @@
{
"name": "robthree/twofactorauth",
"description": "Two Factor Authentication",
- "version": "1.6.1",
+ "version": "1.7.0",
"type": "library",
"keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ],
"homepage": "https://github.com/RobThree/TwoFactorAuth",
@@ -18,7 +18,7 @@
"source": "https://github.com/RobThree/TwoFactorAuth"
},
"require": {
- "php": ">=5.3.0"
+ "php": ">=5.6.0"
},
"require-dev": {
"phpunit/phpunit": "@stable"
diff --git a/vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleQRCodeProvider.php b/vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php
similarity index 78%
rename from vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleQRCodeProvider.php
rename to vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php
index 19e086b..cc094c3 100644
--- a/vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleQRCodeProvider.php
+++ b/vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php
@@ -2,8 +2,8 @@
namespace RobThree\Auth\Providers\Qr;
-// https://developers.google.com/chart/infographics/docs/qr_codes
-class GoogleQRCodeProvider extends BaseHTTPQRCodeProvider
+// https://image-charts.com
+class ImageChartsQRCodeProvider extends BaseHTTPQRCodeProvider
{
public $errorcorrectionlevel;
public $margin;
@@ -31,8 +31,8 @@ public function getQRCodeImage($qrtext, $size)
public function getUrl($qrtext, $size)
{
- return 'https://chart.googleapis.com/chart?cht=qr'
- . '&chs=' . $size . 'x' . $size
+ return 'https://image-charts.com/chart?cht=qr'
+ . '&chs=' . ceil($size/2) . 'x' . ceil($size/2)
. '&chld=' . $this->errorcorrectionlevel . '|' . $this->margin
. '&chl=' . rawurlencode($qrtext);
}
diff --git a/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php b/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php
index ca6e859..eb42577 100644
--- a/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php
+++ b/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php
@@ -17,7 +17,7 @@ public function getRandomBytes($bytecount) {
$hash = mt_rand();
for ($i = 0; $i < $bytecount; $i++) {
$hash = hash($this->algorithm, $hash.mt_rand(), true);
- $result .= $hash[mt_rand(0, sizeof($hash))];
+ $result .= $hash[mt_rand(0, strlen($hash)-1)];
}
return $result;
}
diff --git a/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php b/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php
index 1f55fa3..0eeab2c 100644
--- a/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php
+++ b/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php
@@ -11,7 +11,7 @@ function __construct($source = MCRYPT_DEV_URANDOM) {
}
public function getRandomBytes($bytecount) {
- $result = mcrypt_create_iv($bytecount, $this->source);
+ $result = @mcrypt_create_iv($bytecount, $this->source);
if ($result === false)
throw new \RNGException('mcrypt_create_iv returned an invalid value');
return $result;
diff --git a/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php b/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php
deleted file mode 100644
index 9a775fc..0000000
--- a/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php
+++ /dev/null
@@ -1,15 +0,0 @@
-timestamp))
- throw new \TimeException('Unable to retrieve time from convert-unix-time.com');
- return $json->timestamp;
- }
-}
\ No newline at end of file
diff --git a/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php b/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php
new file mode 100644
index 0000000..d69a3a6
--- /dev/null
+++ b/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php
@@ -0,0 +1,54 @@
+host = $host;
+
+ if (!is_int($port) || $port <= 0 || $port > 65535)
+ throw new \TimeException('Port must be 0 < port < 65535');
+ $this->port = $port;
+
+ if (!is_int($timeout) || $timeout < 0)
+ throw new \TimeException('Timeout must be >= 0');
+ $this->timeout = $timeout;
+ }
+
+ public function getTime() {
+ try {
+ /* Create a socket and connect to NTP server */
+ $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+ socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, ['sec' => $this->timeout, 'usec' => 0]);
+ socket_connect($sock, $this->host, $this->port);
+
+ /* Send request */
+ $msg = "\010" . str_repeat("\0", 47);
+ socket_send($sock, $msg, strlen($msg), 0);
+
+ /* Receive response and close socket */
+ if (socket_recv($sock, $recv, 48, MSG_WAITALL) === false)
+ throw new \Exception(socket_strerror(socket_last_error($sock)));
+ socket_close($sock);
+
+ /* Interpret response */
+ $data = unpack('N12', $recv);
+ $timestamp = sprintf('%u', $data[9]);
+
+ /* NTP is number of seconds since 0000 UT on 1 January 1900 Unix time is seconds since 0000 UT on 1 January 1970 */
+ return $timestamp - 2208988800;
+ }
+ catch (Exception $ex) {
+ throw new \TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->host, $ex->getMessage()));
+ }
+ }
+}
diff --git a/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php b/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php
index e6a1fa9..7bc067d 100644
--- a/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php
+++ b/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php
@@ -79,16 +79,23 @@ public function getCode($secret, $time = null)
/**
* Check if the code is correct. This will accept codes starting from ($discrepancy * $period) sec ago to ($discrepancy * period) sec from now
*/
- public function verifyCode($secret, $code, $discrepancy = 1, $time = null)
+ public function verifyCode($secret, $code, $discrepancy = 1, $time = null, &$timeslice = 0)
{
- $result = false;
$timetamp = $this->getTime($time);
- // To keep safe from timing-attachs we iterate *all* possible codes even though we already may have verified a code is correct
- for ($i = -$discrepancy; $i <= $discrepancy; $i++)
- $result |= $this->codeEquals($this->getCode($secret, $timetamp + ($i * $this->period)), $code);
+ $timeslice = 0;
- return (bool)$result;
+ // To keep safe from timing-attacks we iterate *all* possible codes even though we already may have
+ // verified a code is correct. We use the timeslice variable to hold either 0 (no match) or the timeslice
+ // of the match. Each iteration we either set the timeslice variable to the timeslice of the match
+ // or set the value to itself. This is an effort to maintain constant execution time for the code.
+ for ($i = -$discrepancy; $i <= $discrepancy; $i++) {
+ $ts = $timetamp + ($i * $this->period);
+ $slice = $this->getTimeSlice($ts);
+ $timeslice = $this->codeEquals($this->getCode($secret, $ts), $code) ? $slice : $timeslice;
+ }
+
+ return $timeslice > 0;
}
/**
@@ -134,7 +141,7 @@ public function ensureCorrectTime(array $timeproviders = null, $leniency = 5)
if ($timeproviders == null)
$timeproviders = array(
- new Providers\Time\ConvertUnixTimeDotComTimeProvider(),
+ new Providers\Time\NTPTimeProvider(),
new Providers\Time\HttpTimeProvider()
);
@@ -205,7 +212,7 @@ public function getQrCodeProvider()
{
// Set default QR Code provider if none was specified
if (null === $this->qrcodeprovider) {
- return $this->qrcodeprovider = new Providers\Qr\GoogleQRCodeProvider();
+ return $this->qrcodeprovider = new Providers\Qr\QRServerProvider();
}
return $this->qrcodeprovider;
}
diff --git a/vendor/robthree/twofactorauth/phpunit.xml b/vendor/robthree/twofactorauth/phpunit.xml
new file mode 100644
index 0000000..92c3a27
--- /dev/null
+++ b/vendor/robthree/twofactorauth/phpunit.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ ./tests
+
+
+
+
+ ./lib
+
+
+
\ No newline at end of file
diff --git a/vendor/robthree/twofactorauth/phpunit.xml.tmppica b/vendor/robthree/twofactorauth/phpunit.xml.tmppica
new file mode 100644
index 0000000..e69de29
diff --git a/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php b/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php
index 587b19b..a0f2f67 100644
--- a/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php
+++ b/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php
@@ -4,7 +4,7 @@
require_once 'lib/Providers/Qr/IQRCodeProvider.php';
require_once 'lib/Providers/Qr/BaseHTTPQRCodeProvider.php';
-require_once 'lib/Providers/Qr/GoogleQRCodeProvider.php';
+require_once 'lib/Providers/Qr/ImageChartsQRCodeProvider.php';
require_once 'lib/Providers/Qr/QRException.php';
require_once 'lib/Providers/Rng/IRNGProvider.php';
@@ -18,7 +18,7 @@
require_once 'lib/Providers/Time/ITimeProvider.php';
require_once 'lib/Providers/Time/LocalMachineTimeProvider.php';
require_once 'lib/Providers/Time/HttpTimeProvider.php';
-require_once 'lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php';
+require_once 'lib/Providers/Time/NTPTimeProvider.php';
require_once 'lib/Providers/Time/TimeException.php';
use RobThree\Auth\TwoFactorAuth;
@@ -124,7 +124,8 @@ public function testEnsureDefaultTimeProviderReturnsCorrectTime() {
public function testEnsureAllTimeProvidersReturnCorrectTime() {
$tfa = new TwoFactorAuth('Test', 6, 30, 'sha1');
$tfa->ensureCorrectTime(array(
- new RobThree\Auth\Providers\Time\ConvertUnixTimeDotComTimeProvider(),
+ new RobThree\Auth\Providers\Time\NTPTimeProvider(), // Uses pool.ntp.org by default
+ //new RobThree\Auth\Providers\Time\NTPTimeProvider('time.google.com'), // Somehow time.google.com and time.windows.com make travis timeout??
new RobThree\Auth\Providers\Time\HttpTimeProvider(), // Uses google.com by default
new RobThree\Auth\Providers\Time\HttpTimeProvider('https://github.com'),
new RobThree\Auth\Providers\Time\HttpTimeProvider('https://yahoo.com'),
@@ -150,6 +151,31 @@ public function testVerifyCodeWorksCorrectly() {
$this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 - 65)); //Test discrepancy
}
+ public function testVerifyCorrectTimeSliceIsReturned() {
+ $tfa = new TwoFactorAuth('Test', 6, 30);
+
+ // We test with discrepancy 3 (so total of 7 codes: c-3, c-2, c-1, c, c+1, c+2, c+3
+ // Ensure each corresponding timeslice is returned correctly
+ $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '534113', 3, 1426847190, $timeslice1));
+ $this->assertEquals(47561570, $timeslice1);
+ $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '819652', 3, 1426847190, $timeslice2));
+ $this->assertEquals(47561571, $timeslice2);
+ $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '915954', 3, 1426847190, $timeslice3));
+ $this->assertEquals(47561572, $timeslice3);
+ $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 3, 1426847190, $timeslice4));
+ $this->assertEquals(47561573, $timeslice4);
+ $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '348401', 3, 1426847190, $timeslice5));
+ $this->assertEquals(47561574, $timeslice5);
+ $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '648525', 3, 1426847190, $timeslice6));
+ $this->assertEquals(47561575, $timeslice6);
+ $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '170645', 3, 1426847190, $timeslice7));
+ $this->assertEquals(47561576, $timeslice7);
+
+ // Incorrect code should return false and a 0 timeslice
+ $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '111111', 3, 1426847190, $timeslice8));
+ $this->assertEquals(0, $timeslice8);
+ }
+
public function testTotpUriIsCorrect() {
$qr = new TestQrProvider();
@@ -295,10 +321,12 @@ public function testHashRNGProvidersReturnExpectedNumberOfBytes() {
* @requires function mcrypt_create_iv
*/
public function testMCryptRNGProvidersReturnExpectedNumberOfBytes() {
- $rng = new \RobThree\Auth\Providers\Rng\MCryptRNGProvider();
- foreach ($this->getRngTestLengths() as $l)
- $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
- $this->assertEquals(true, $rng->isCryptographicallySecure());
+ if (function_exists('mcrypt_create_iv')) {
+ $rng = new \RobThree\Auth\Providers\Rng\MCryptRNGProvider();
+ foreach ($this->getRngTestLengths() as $l)
+ $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
+ $this->assertEquals(true, $rng->isCryptographicallySecure());
+ }
}
/**