git subrepo commit (merge) mailcow/src/mailcow-dockerized

subrepo: subdir:   "mailcow/src/mailcow-dockerized"
  merged:   "02ae5285"
upstream: origin:   "https://github.com/mailcow/mailcow-dockerized.git"
  branch:   "master"
  commit:   "649a5c01"
git-subrepo: version:  "0.4.3"
  origin:   "???"
  commit:   "???"
Change-Id: I870ad468fba026cc5abf3c5699ed1e12ff28b32b
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.github/FUNDING.yml b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.github/FUNDING.yml
new file mode 100644
index 0000000..b2d7224
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.github/FUNDING.yml
@@ -0,0 +1,4 @@
+# These are supported funding model platforms
+
+github: [RobThree]
+custom: ["https://paypal.me/robiii"]
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.github/workflows/test.yml b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.github/workflows/test.yml
new file mode 100644
index 0000000..8b31e23
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.github/workflows/test.yml
@@ -0,0 +1,27 @@
+name: Test
+
+on:
+  push:
+  pull_request:
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        php-version: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0']
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - uses: shivammathur/setup-php@v2
+      with:
+        php-version: ${{ matrix.php-version }}
+        tools: composer
+        coverage: xdebug
+
+    - uses: ramsey/composer-install@v1
+
+    - run: composer lint
+    - run: composer test
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.gitignore b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.gitignore
index 8a25841..5c1c961 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.gitignore
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.gitignore
@@ -125,7 +125,7 @@
 # Publish Web Output
 *.[Pp]ublish.xml
 *.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings 
+# TODO: Comment the next line if you want to checkin your web deploy settings
 # but database connection strings (with potential passwords) will be unencrypted
 *.pubxml
 *.publishproj
@@ -184,6 +184,9 @@
 
 # Composer
 /vendor
+composer.lock
 
 # .vs
-.vs/
\ No newline at end of file
+.vs/
+
+.phpunit.result.cache
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml
deleted file mode 100644
index fdc6ff5..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-language: php
-
-php:
-  - 5.6
-  - 7.0
-  - 7.1
-  - 7.2
-  - 7.3
-  - 7.4
-
-before_script:
-  - composer install
-
-script:
-  - vendor/bin/phpunit --coverage-text tests
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/README.md b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/README.md
index 3574ae9..b8fcc75 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/README.md
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/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) [![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/github/workflow/status/RobThree/TwoFactorAuth/Test/master?style=flat-square)](https://github.com/RobThree/TwoFactorAuth/actions?query=branch%3Amaster) [![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,10 +10,15 @@
 
 ## Requirements
 
-* 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.
+* Tested on PHP 5.6 up to 8.0
+* [cURL](http://php.net/manual/en/book.curl.php) when using the provided `QRServerProvider` (default), `ImageChartsQRCodeProvider` 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.
 
+Optionally, you may need:
+
+* [endroid/qr-code](https://github.com/endroid/qr-code) if using `EndroidQrCodeProvider` or `EndroidQrCodeWithLogoProvider`.
+* [bacon/bacon-qr-code](https://github.com/Bacon/BaconQrCode) if using `BaconQrCodeProvider`.
+
 ## Installation
 
 Run the following command:
@@ -35,17 +40,17 @@
 
 The TwoFactorAuth class constructor accepts 7 arguments (all optional):
 
-Argument          | 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
 `$period`         | `30`          | The number of seconds a code will be valid
-`$algorithm`      | `sha1`        | The algorithm used
+`$algorithm`      | `sha1`        | The algorithm used (one of `sha1`, `sha256`, `sha512`, `md5`)
 `$qrcodeprovider` | `null`        | QR-code provider (more on this later)
 `$rngprovider`    | `null`        | Random Number Generator provider (more on this later)
 `$timeprovider`   | `null`        | Time provider (more on this later)
 
-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.
+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 Authenticator 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,9 +69,12 @@
 
 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. `ImageChartsQRCodeProvider` (default)
-2. `QRServerProvider`
+1. `QRServerProvider` (default)
+2. `ImageChartsQRCodeProvider`
 3. `QRicketProvider`
+4. `EndroidQrCodeProvider` (requires `endroid/qr-code` to be installed)
+5. `EndroidQrCodeWithLogoProvider` (same, but supporting embedded images)
+6. `BaconQrCodeProvider` (requires `bacon/bacon-qr-code` to be installed)
 
 ...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.
 
@@ -89,7 +97,9 @@
 $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`, 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.
+If you do extra validations with your `$_POST` values, just make sure the code is still submitted as string - even if that's a numeric code, casting it to integer is unreliable. Also, you may need to store `$secret` in a `$_SESSION` or other persistent storage between requests. `verifyCode()` will return either `true` (the code was valid) or `false` (the code was invalid; no points for you!).
+
+ The `verifyCode()` accepts, aside from `$secret` and `$code`, three more arguments, with 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, `$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.
 
@@ -105,10 +115,10 @@
 
 ````php
 public function __construct(
-    $issuer = null, 
+    $issuer = null,
     $digits = 6,
-    $period = 30, 
-    $algorithm = 'sha1', 
+    $period = 30,
+    $algorithm = 'sha1',
     RobThree\Auth\Providers\Qr\IQRCodeProvider $qrcodeprovider = null,
     RobThree\Auth\Providers\Rng\IRNGProvider $rngprovider = null
 );
@@ -119,9 +129,9 @@
 
 ### 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` 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.
+As mentioned before, this library comes with five '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 five 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 [`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.
+The default provider is the [`QRServerProvider`](lib/Providers/Qr/QRServerProvider.php) which uses the [goqr.me API](http://goqr.me/api/doc/create-qr-code/) to render QR-codes. Then we have 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 and the [`QRicketProvider`](lib/Providers/Qr/QRicketProvider.php) which uses the [QRickit API](http://qrickit.com/qrickit_apps/qrickit_api.php). These three providers all 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. Finally, we have [`EndroidQrCodeProvider`](lib/Providers/Qr/EndroidQrCodeProvider.php), [`EndroidQrCodeWithLogoProvider`](lib/Providers/Qr/EndroidQrCodeWithLogoProvider.php) and [`BaconQrCodeProvider`](lib/Providers/Qr/BaconQrCodeProvider.php) which require an optional dependency to be installed to use (see Requirements section above), but will generate the QR codes locally. All five 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:
 
@@ -148,7 +158,7 @@
   public function getMimeType() {
     return 'image/png';                             // This provider only returns PNG's
   }
-  
+
   public function getQRCodeImage($qrtext, $size) {
     ob_start();                                     // 'Catch' QRCode's output
     QRCode::png($qrtext, null, QR_ECLEVEL_L, 3, 4); // We ignore $size and set it to 3
@@ -190,7 +200,7 @@
 
 ## Integrations
 
-- [CakePHP 3](https://github.com/andrej-griniuk/cakephp-two-factor-auth) 
+- [CakePHP 3](https://github.com/andrej-griniuk/cakephp-two-factor-auth)
 
 ## License
 
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json
index 50f8b86..847b2f8 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json
@@ -1,7 +1,7 @@
 {
     "name": "robthree/twofactorauth",
     "description": "Two Factor Authentication",
-    "version": "1.7.0",
+    "version": "1.8.0",
     "type": "library",
     "keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ],
     "homepage": "https://github.com/RobThree/TwoFactorAuth",
@@ -21,7 +21,12 @@
         "php": ">=5.6.0"
     },
     "require-dev": {
-        "phpunit/phpunit": "@stable"
+        "phpunit/phpunit": "@stable",
+        "php-parallel-lint/php-parallel-lint": "^1.2"
+    },
+    "suggest": {
+        "bacon/bacon-qr-code": "Needed for BaconQrCodeProvider provider",
+        "endroid/qr-code": "Needed for EndroidQrCodeProvider"
     },
     "autoload": {
         "psr-4": {
@@ -30,7 +35,15 @@
     },
     "autoload-dev": {
         "psr-4": {
-            "RobThree\\Auth\\Test\\": "tests"
+            "Tests\\": "tests/"
         }
+    },
+    "scripts": {
+        "lint": [
+            "parallel-lint --exclude vendor ."
+        ],
+        "test": [
+            "XDEBUG_MODE=coverage phpunit"
+        ]
     }
 }
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/composer.lock b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/composer.lock
deleted file mode 100644
index 63df937..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/composer.lock
+++ /dev/null
@@ -1,980 +0,0 @@
-{
-    "_readme": [
-        "This file locks the dependencies of your project to a known state",
-        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
-        "This file is @generated automatically"
-    ],
-    "content-hash": "9647de85f54ba6db237f5ff42ff85a1f",
-    "packages": [],
-    "packages-dev": [
-        {
-            "name": "doctrine/instantiator",
-            "version": "1.0.5",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
-                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3,<8.0-DEV"
-            },
-            "require-dev": {
-                "athletic/athletic": "~0.1.8",
-                "ext-pdo": "*",
-                "ext-phar": "*",
-                "phpunit/phpunit": "~4.0",
-                "squizlabs/php_codesniffer": "~2.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Marco Pivetta",
-                    "email": "ocramius@gmail.com",
-                    "homepage": "http://ocramius.github.com/"
-                }
-            ],
-            "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
-            "homepage": "https://github.com/doctrine/instantiator",
-            "keywords": [
-                "constructor",
-                "instantiate"
-            ],
-            "time": "2015-06-14T21:17:01+00:00"
-        },
-        {
-            "name": "phpdocumentor/reflection-docblock",
-            "version": "2.0.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
-                "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.0"
-            },
-            "suggest": {
-                "dflydev/markdown": "~1.0",
-                "erusev/parsedown": "~1.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "phpDocumentor": [
-                        "src/"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Mike van Riel",
-                    "email": "mike.vanriel@naenius.com"
-                }
-            ],
-            "time": "2015-02-03T12:10:50+00:00"
-        },
-        {
-            "name": "phpspec/prophecy",
-            "version": "v1.6.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
-                "reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/instantiator": "^1.0.2",
-                "php": "^5.3|^7.0",
-                "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
-                "sebastian/comparator": "^1.1",
-                "sebastian/recursion-context": "^1.0|^2.0"
-            },
-            "require-dev": {
-                "phpspec/phpspec": "^2.0",
-                "phpunit/phpunit": "^4.8 || ^5.6.5"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.6.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Prophecy\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Konstantin Kudryashov",
-                    "email": "ever.zet@gmail.com",
-                    "homepage": "http://everzet.com"
-                },
-                {
-                    "name": "Marcello Duarte",
-                    "email": "marcello.duarte@gmail.com"
-                }
-            ],
-            "description": "Highly opinionated mocking framework for PHP 5.3+",
-            "homepage": "https://github.com/phpspec/prophecy",
-            "keywords": [
-                "Double",
-                "Dummy",
-                "fake",
-                "mock",
-                "spy",
-                "stub"
-            ],
-            "time": "2016-11-21T14:58:47+00:00"
-        },
-        {
-            "name": "phpunit/php-code-coverage",
-            "version": "2.2.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3",
-                "phpunit/php-file-iterator": "~1.3",
-                "phpunit/php-text-template": "~1.2",
-                "phpunit/php-token-stream": "~1.3",
-                "sebastian/environment": "^1.3.2",
-                "sebastian/version": "~1.0"
-            },
-            "require-dev": {
-                "ext-xdebug": ">=2.1.4",
-                "phpunit/phpunit": "~4"
-            },
-            "suggest": {
-                "ext-dom": "*",
-                "ext-xdebug": ">=2.2.1",
-                "ext-xmlwriter": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.2.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
-            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
-            "keywords": [
-                "coverage",
-                "testing",
-                "xunit"
-            ],
-            "time": "2015-10-06T15:47:00+00:00"
-        },
-        {
-            "name": "phpunit/php-file-iterator",
-            "version": "1.4.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
-                "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
-            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
-            "keywords": [
-                "filesystem",
-                "iterator"
-            ],
-            "time": "2016-10-03T07:40:28+00:00"
-        },
-        {
-            "name": "phpunit/php-text-template",
-            "version": "1.2.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-text-template.git",
-                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
-                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Simple template engine.",
-            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
-            "keywords": [
-                "template"
-            ],
-            "time": "2015-06-21T13:50:34+00:00"
-        },
-        {
-            "name": "phpunit/php-timer",
-            "version": "1.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-timer.git",
-                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
-                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4|~5"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Utility class for timing",
-            "homepage": "https://github.com/sebastianbergmann/php-timer/",
-            "keywords": [
-                "timer"
-            ],
-            "time": "2016-05-12T18:03:57+00:00"
-        },
-        {
-            "name": "phpunit/php-token-stream",
-            "version": "1.4.9",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
-                "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
-                "shasum": ""
-            },
-            "require": {
-                "ext-tokenizer": "*",
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.2"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Wrapper around PHP's tokenizer extension.",
-            "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
-            "keywords": [
-                "tokenizer"
-            ],
-            "time": "2016-11-15T14:06:22+00:00"
-        },
-        {
-            "name": "phpunit/phpunit",
-            "version": "4.8.35",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/791b1a67c25af50e230f841ee7a9c6eba507dc87",
-                "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-json": "*",
-                "ext-pcre": "*",
-                "ext-reflection": "*",
-                "ext-spl": "*",
-                "php": ">=5.3.3",
-                "phpspec/prophecy": "^1.3.1",
-                "phpunit/php-code-coverage": "~2.1",
-                "phpunit/php-file-iterator": "~1.4",
-                "phpunit/php-text-template": "~1.2",
-                "phpunit/php-timer": "^1.0.6",
-                "phpunit/phpunit-mock-objects": "~2.3",
-                "sebastian/comparator": "~1.2.2",
-                "sebastian/diff": "~1.2",
-                "sebastian/environment": "~1.3",
-                "sebastian/exporter": "~1.2",
-                "sebastian/global-state": "~1.0",
-                "sebastian/version": "~1.0",
-                "symfony/yaml": "~2.1|~3.0"
-            },
-            "suggest": {
-                "phpunit/php-invoker": "~1.1"
-            },
-            "bin": [
-                "phpunit"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.8.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "The PHP Unit Testing framework.",
-            "homepage": "https://phpunit.de/",
-            "keywords": [
-                "phpunit",
-                "testing",
-                "xunit"
-            ],
-            "time": "2017-02-06T05:18:07+00:00"
-        },
-        {
-            "name": "phpunit/phpunit-mock-objects",
-            "version": "2.3.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/instantiator": "^1.0.2",
-                "php": ">=5.3.3",
-                "phpunit/php-text-template": "~1.2",
-                "sebastian/exporter": "~1.2"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.4"
-            },
-            "suggest": {
-                "ext-soap": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.3.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Mock Object library for PHPUnit",
-            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
-            "keywords": [
-                "mock",
-                "xunit"
-            ],
-            "time": "2015-10-02T06:51:40+00:00"
-        },
-        {
-            "name": "sebastian/comparator",
-            "version": "1.2.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
-                "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3",
-                "sebastian/diff": "~1.2",
-                "sebastian/exporter": "~1.2 || ~2.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.2.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Volker Dusch",
-                    "email": "github@wallbash.com"
-                },
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@2bepublished.at"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides the functionality to compare PHP values for equality",
-            "homepage": "http://www.github.com/sebastianbergmann/comparator",
-            "keywords": [
-                "comparator",
-                "compare",
-                "equality"
-            ],
-            "time": "2017-01-29T09:50:25+00:00"
-        },
-        {
-            "name": "sebastian/diff",
-            "version": "1.4.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
-                "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.8"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Kore Nordmann",
-                    "email": "mail@kore-nordmann.de"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Diff implementation",
-            "homepage": "https://github.com/sebastianbergmann/diff",
-            "keywords": [
-                "diff"
-            ],
-            "time": "2015-12-08T07:14:41+00:00"
-        },
-        {
-            "name": "sebastian/environment",
-            "version": "1.3.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
-                "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.3.3 || ^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.8 || ^5.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.3.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides functionality to handle HHVM/PHP environments",
-            "homepage": "http://www.github.com/sebastianbergmann/environment",
-            "keywords": [
-                "Xdebug",
-                "environment",
-                "hhvm"
-            ],
-            "time": "2016-08-18T05:49:44+00:00"
-        },
-        {
-            "name": "sebastian/exporter",
-            "version": "1.2.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3",
-                "sebastian/recursion-context": "~1.0"
-            },
-            "require-dev": {
-                "ext-mbstring": "*",
-                "phpunit/phpunit": "~4.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.3.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Volker Dusch",
-                    "email": "github@wallbash.com"
-                },
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@2bepublished.at"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                },
-                {
-                    "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
-                }
-            ],
-            "description": "Provides the functionality to export PHP variables for visualization",
-            "homepage": "http://www.github.com/sebastianbergmann/exporter",
-            "keywords": [
-                "export",
-                "exporter"
-            ],
-            "time": "2016-06-17T09:04:28+00:00"
-        },
-        {
-            "name": "sebastian/global-state",
-            "version": "1.1.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
-                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.2"
-            },
-            "suggest": {
-                "ext-uopz": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Snapshotting of global state",
-            "homepage": "http://www.github.com/sebastianbergmann/global-state",
-            "keywords": [
-                "global state"
-            ],
-            "time": "2015-10-12T03:26:01+00:00"
-        },
-        {
-            "name": "sebastian/recursion-context",
-            "version": "1.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "913401df809e99e4f47b27cdd781f4a258d58791"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
-                "reference": "913401df809e99e4f47b27cdd781f4a258d58791",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                },
-                {
-                    "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
-                }
-            ],
-            "description": "Provides functionality to recursively process PHP variables",
-            "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
-            "time": "2015-11-11T19:50:13+00:00"
-        },
-        {
-            "name": "sebastian/version",
-            "version": "1.0.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
-                "shasum": ""
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
-            "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2015-06-21T13:59:46+00:00"
-        },
-        {
-            "name": "symfony/yaml",
-            "version": "v2.8.17",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/yaml.git",
-                "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/322a8c2dfbca15ad6b1b27e182899f98ec0e0153",
-                "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.9"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.8-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Yaml\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Yaml Component",
-            "homepage": "https://symfony.com",
-            "time": "2017-01-21T16:40:50+00:00"
-        }
-    ],
-    "aliases": [],
-    "minimum-stability": "stable",
-    "stability-flags": {
-        "phpunit/phpunit": 0
-    },
-    "prefer-stable": false,
-    "prefer-lowest": false,
-    "platform": {
-        "php": ">=5.3.0"
-    },
-    "platform-dev": []
-}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/BaconQrCodeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/BaconQrCodeProvider.php
new file mode 100644
index 0000000..4d5cf01
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/BaconQrCodeProvider.php
@@ -0,0 +1,152 @@
+<?php
+
+namespace RobThree\Auth\Providers\Qr;
+
+use BaconQrCode\Writer;
+use BaconQrCode\Renderer\ImageRenderer;
+use BaconQrCode\Renderer\RendererStyle\RendererStyle;
+use BaconQrCode\Renderer\RendererStyle\Fill;
+use BaconQrCode\Renderer\Color\Rgb;
+use BaconQrCode\Renderer\RendererStyle\EyeFill;
+
+use BaconQrCode\Renderer\Image\EpsImageBackEnd;
+use BaconQrCode\Renderer\Image\ImageBackEndInterface;
+use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
+use BaconQrCode\Renderer\Image\SvgImageBackEnd;
+
+class BaconQrCodeProvider implements IQRCodeProvider
+{
+    private $borderWidth = 4; // default from Bacon QR Code
+    private $backgroundColour;
+    private $foregroundColour;
+    private $format;
+
+    /**
+     * Ensure we using the latest Bacon QR Code and specify default options
+     *
+     * @param int $borderWidth space around the QR code, 4 is the default from Bacon QR Code
+     * @param string $backgroundColour hex reference for the background colour
+     * @param string $foregroundColour hex reference for the foreground colour
+     * @param string $format the desired output, png or svg
+     */
+    public function __construct($borderWidth = 4, $backgroundColour = '#ffffff', $foregroundColour = '#000000', $format = 'png')
+    {
+        if (! class_exists(ImagickImageBackEnd::class)) {
+            throw new \RuntimeException('Make sure you are using version 2 of Bacon QR Code');
+        }
+
+        $this->borderWidth = $borderWidth;
+        $this->backgroundColour = $this->handleColour($backgroundColour);
+        $this->foregroundColour = $this->handleColour($foregroundColour);
+        $this->format = strtolower($format);
+    }
+
+    /**
+     * Standard functions from IQRCodeProvider
+     */
+
+    public function getMimeType()
+    {
+        switch ($this->format) {
+            case 'png':
+                return 'image/png';
+            case 'gif':
+                return 'image/gif';
+            case 'jpg':
+            case 'jpeg':
+                return 'image/jpeg';
+            case 'svg':
+                return 'image/svg+xml';
+            case 'eps':
+                return 'application/postscript';
+        }
+
+        throw new \RuntimeException(sprintf('Unknown MIME-type: %s', $this->format));
+    }
+
+    public function getQRCodeImage($qrText, $size)
+    {
+        switch ($this->format) {
+            case 'svg':
+                $backend = new SvgImageBackEnd;
+                break;
+            case 'eps':
+                $backend = new EpsImageBackEnd;
+                break;
+            default:
+                $backend = new ImagickImageBackEnd($this->format);
+        }
+
+        $output = $this->getQRCodeByBackend($qrText, $size, $backend);
+
+        if ($this->format == 'svg') {
+            $svg = explode("\n", $output);
+            return $svg[1];
+        }
+
+        return $output;
+    }
+
+    /**
+     * Abstract QR code generation function
+     * providing colour changing support
+     */
+    private function getQRCodeByBackend($qrText, $size, ImageBackEndInterface $backend)
+    {
+        $rendererStyleArgs = array($size, $this->borderWidth);
+
+        if (is_array($this->foregroundColour) && is_array($this->backgroundColour)) {
+            $rendererStyleArgs = array_merge($rendererStyleArgs, array(
+                null,
+                null,
+                Fill::withForegroundColor(
+                    new Rgb(...$this->backgroundColour),
+                    new Rgb(...$this->foregroundColour),
+                    new EyeFill(null, null),
+                    new EyeFill(null, null),
+                    new EyeFill(null, null)
+                )
+            ));
+        }
+
+        $writer = new Writer(new ImageRenderer(
+            new RendererStyle(...$rendererStyleArgs),
+            $backend
+        ));
+
+        return $writer->writeString($qrText);
+    }
+
+    /**
+     * Ensure colour is an array of three values but also
+     * accept a string and assume its a 3 or 6 character hex
+     */
+    private function handleColour($colour)
+    {
+        if (is_string($colour) && $colour[0] == '#') {
+            $hexToRGB = function ($input) {
+                // split the array into three chunks
+                $split = str_split(trim($input, '#'), strlen($input) / 3);
+
+                // cope with three character hex reference
+                // three characters plus a # = 4
+                if (strlen($input) == 4) {
+                    array_walk($split, function (&$character) {
+                        $character = str_repeat($character, 2);
+                    });
+                }
+
+                // convert hex to rgb
+                return array_map('hexdec', $split);
+            };
+
+            return $hexToRGB($colour);
+        }
+
+        if (is_array($colour) && count($colour) == 3) {
+            return $colour;
+        }
+
+        throw new \RuntimeException('Invalid colour value');
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php
index 5cb3add..bcc8d56 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php
@@ -4,12 +4,18 @@
 
 abstract class BaseHTTPQRCodeProvider implements IQRCodeProvider
 {
+    /** @var bool */
     protected $verifyssl;
 
+    /**
+     * @param string $url
+     *
+     * @return string|bool
+     */
     protected function getContent($url)
     {
         $curlhandle = curl_init();
-        
+
         curl_setopt_array($curlhandle, array(
             CURLOPT_URL => $url,
             CURLOPT_RETURNTRANSFER => true,
@@ -20,8 +26,8 @@
             CURLOPT_USERAGENT => 'TwoFactorAuth'
         ));
         $data = curl_exec($curlhandle);
-        
+
         curl_close($curlhandle);
         return $data;
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeProvider.php
new file mode 100755
index 0000000..810aa9b
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeProvider.php
@@ -0,0 +1,70 @@
+<?php
+namespace RobThree\Auth\Providers\Qr;
+
+use Endroid\QrCode\ErrorCorrectionLevel;
+use Endroid\QrCode\QrCode;
+
+class EndroidQrCodeProvider implements IQRCodeProvider
+{
+    public $bgcolor;
+    public $color;
+    public $margin;
+    public $errorcorrectionlevel;
+
+    public function __construct($bgcolor = 'ffffff', $color = '000000', $margin = 0, $errorcorrectionlevel = 'H')
+    {
+        $this->bgcolor = $this->handleColor($bgcolor);
+        $this->color = $this->handleColor($color);
+        $this->margin = $margin;
+        $this->errorcorrectionlevel = $this->handleErrorCorrectionLevel($errorcorrectionlevel);
+    }
+
+    public function getMimeType()
+    {
+        return 'image/png';
+    }
+
+    public function getQRCodeImage($qrtext, $size)
+    {
+        return $this->qrCodeInstance($qrtext, $size)->writeString();
+    }
+
+    protected function qrCodeInstance($qrtext, $size)
+    {
+        $qrCode = new QrCode($qrtext);
+        $qrCode->setSize($size);
+
+        $qrCode->setErrorCorrectionLevel($this->errorcorrectionlevel);
+        $qrCode->setMargin($this->margin);
+        $qrCode->setBackgroundColor($this->bgcolor);
+        $qrCode->setForegroundColor($this->color);
+
+        return $qrCode;
+    }
+
+    private function handleColor($color)
+    {
+        $split = str_split($color, 2);
+        $r = hexdec($split[0]);
+        $g = hexdec($split[1]);
+        $b = hexdec($split[2]);
+
+        return ['r' => $r, 'g' => $g, 'b' => $b, 'a' => 0];
+    }
+
+    private function handleErrorCorrectionLevel($level)
+    {
+        switch ($level) {
+            case 'L':
+                return ErrorCorrectionLevel::LOW();
+            case 'M':
+                return ErrorCorrectionLevel::MEDIUM();
+            case 'Q':
+                return ErrorCorrectionLevel::QUARTILE();
+            case 'H':
+                return ErrorCorrectionLevel::HIGH();
+            default:
+                return ErrorCorrectionLevel::HIGH();
+        }
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeWithLogoProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeWithLogoProvider.php
new file mode 100755
index 0000000..ed8cc98
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeWithLogoProvider.php
@@ -0,0 +1,35 @@
+<?php
+namespace RobThree\Auth\Providers\Qr;
+
+use Endroid\QrCode\ErrorCorrectionLevel;
+use Endroid\QrCode\QrCode;
+
+class EndroidQrCodeWithLogoProvider extends EndroidQrCodeProvider
+{
+    protected $logoPath;
+    protected $logoSize;
+
+    /**
+     * Adds an image to the middle of the QR Code.
+     * @param string $path Path to an image file
+     * @param array|int $size Just the width, or [width, height]
+     */
+    public function setLogo($path, $size = null)
+    {
+        $this->logoPath = $path;
+        $this->logoSize = (array)$size;
+    }
+
+    protected function qrCodeInstance($qrtext, $size) {
+        $qrCode = parent::qrCodeInstance($qrtext, $size);
+
+        if ($this->logoPath) {
+            $qrCode->setLogoPath($this->logoPath);
+            if ($this->logoSize) {
+                $qrCode->setLogoSize($this->logoSize[0], $this->logoSize[1]);
+            }
+        }
+
+        return $qrCode;
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php
index 83ed67b..e53a5ad 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php
@@ -4,6 +4,21 @@
 
 interface IQRCodeProvider
 {
+    /**
+     * Generate and return the QR code to embed in a web page
+     *
+     * @param string $qrtext the value to encode in the QR code
+     * @param int $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
     public function getQRCodeImage($qrtext, $size);
+
+    /**
+     * Returns the appropriate mime type for the QR code
+     * that will be generated
+     *
+     * @return string
+     */
     public function getMimeType();
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php
index cc094c3..ea46ed4 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php
@@ -3,37 +3,58 @@
 namespace RobThree\Auth\Providers\Qr;
 
 // https://image-charts.com
-class ImageChartsQRCodeProvider extends BaseHTTPQRCodeProvider 
+class ImageChartsQRCodeProvider extends BaseHTTPQRCodeProvider
 {
+    /** @var string */
     public $errorcorrectionlevel;
+
+    /** @var int */
     public $margin;
 
-    function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 1) 
+    /**
+     * @param bool $verifyssl
+     * @param string $errorcorrectionlevel
+     * @param int $margin
+     */
+    public function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 1)
     {
-        if (!is_bool($verifyssl))
-            throw new \QRException('VerifySSL must be bool');
+        if (!is_bool($verifyssl)) {
+            throw new QRException('VerifySSL must be bool');
+        }
 
         $this->verifyssl = $verifyssl;
-        
+
         $this->errorcorrectionlevel = $errorcorrectionlevel;
         $this->margin = $margin;
     }
-    
-    public function getMimeType() 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimeType()
     {
         return 'image/png';
     }
-    
-    public function getQRCodeImage($qrtext, $size) 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getQRCodeImage($qrtext, $size)
     {
         return $this->getContent($this->getUrl($qrtext, $size));
     }
-    
-    public function getUrl($qrtext, $size) 
+
+    /**
+     * @param string $qrtext the value to encode in the QR code
+     * @param int $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
+    public function getUrl($qrtext, $size)
     {
         return 'https://image-charts.com/chart?cht=qr'
-            . '&chs=' . ceil($size/2) . 'x' . ceil($size/2)
+            . '&chs=' . ceil($size / 2) . 'x' . ceil($size / 2)
             . '&chld=' . $this->errorcorrectionlevel . '|' . $this->margin
             . '&chl=' . rawurlencode($qrtext);
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRException.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRException.php
index c28e829..4e75f77 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRException.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRException.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace RobThree\Auth\Providers\Qr;
+
 use RobThree\Auth\TwoFactorAuthException;
 
-class QRException extends TwoFactorAuthException {}
\ No newline at end of file
+class QRException extends TwoFactorAuthException {}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRServerProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRServerProvider.php
index 928b87b..2252dfc 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRServerProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRServerProvider.php
@@ -3,22 +3,43 @@
 namespace RobThree\Auth\Providers\Qr;
 
 // http://goqr.me/api/doc/create-qr-code/
-class QRServerProvider extends BaseHTTPQRCodeProvider 
+class QRServerProvider extends BaseHTTPQRCodeProvider
 {
+    /** @var string */
     public $errorcorrectionlevel;
+
+    /** @var int */
     public $margin;
+
+    /** @var int */
     public $qzone;
+
+    /** @var string */
     public $bgcolor;
+
+    /** @var string */
     public $color;
+
+    /** @var string */
     public $format;
 
-    function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 4, $qzone = 1, $bgcolor = 'ffffff', $color = '000000', $format = 'png') 
+    /**
+     * @param bool $verifyssl
+     * @param string $errorcorrectionlevel
+     * @param int $margin
+     * @param int $qzone
+     * @param string $bgcolor
+     * @param string $color
+     * @param string $format
+     */
+    public function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 4, $qzone = 1, $bgcolor = 'ffffff', $color = '000000', $format = 'png')
     {
-        if (!is_bool($verifyssl))
+        if (!is_bool($verifyssl)) {
             throw new QRException('VerifySSL must be bool');
+        }
 
         $this->verifyssl = $verifyssl;
-        
+
         $this->errorcorrectionlevel = $errorcorrectionlevel;
         $this->margin = $margin;
         $this->qzone = $qzone;
@@ -26,37 +47,53 @@
         $this->color = $color;
         $this->format = $format;
     }
-    
-    public function getMimeType() 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimeType()
     {
-        switch (strtolower($this->format))
-        {
-        	case 'png':
+        switch (strtolower($this->format)) {
+            case 'png':
                 return 'image/png';
-        	case 'gif':
+            case 'gif':
                 return 'image/gif';
-        	case 'jpg':
-        	case 'jpeg':
+            case 'jpg':
+            case 'jpeg':
                 return 'image/jpeg';
-        	case 'svg':
+            case 'svg':
                 return 'image/svg+xml';
-        	case 'eps':
+            case 'eps':
                 return 'application/postscript';
         }
-        throw new \QRException(sprintf('Unknown MIME-type: %s', $this->format));
+        throw new QRException(sprintf('Unknown MIME-type: %s', $this->format));
     }
-    
-    public function getQRCodeImage($qrtext, $size) 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getQRCodeImage($qrtext, $size)
     {
         return $this->getContent($this->getUrl($qrtext, $size));
     }
-    
-    private function decodeColor($value) 
+
+    /**
+     * @param string $value
+     *
+     * @return string
+     */
+    private function decodeColor($value)
     {
         return vsprintf('%d-%d-%d', sscanf($value, "%02x%02x%02x"));
     }
-    
-    public function getUrl($qrtext, $size) 
+
+    /**
+     * @param string $qrtext the value to encode in the QR code
+     * @param int|string $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
+    public function getUrl($qrtext, $size)
     {
         return 'https://api.qrserver.com/v1/create-qr-code/'
             . '?size=' . $size . 'x' . $size
@@ -68,4 +105,4 @@
             . '&format=' . strtolower($this->format)
             . '&data=' . rawurlencode($qrtext);
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php
index 59e27cc..166a8a9 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php
@@ -3,45 +3,67 @@
 namespace RobThree\Auth\Providers\Qr;
 
 // http://qrickit.com/qrickit_apps/qrickit_api.php
-class QRicketProvider extends BaseHTTPQRCodeProvider 
+class QRicketProvider extends BaseHTTPQRCodeProvider
 {
+    /** @var string */
     public $errorcorrectionlevel;
-    public $margin;
-    public $qzone;
+
+    /** @var string */
     public $bgcolor;
+
+    /** @var string */
     public $color;
+
+    /** @var string */
     public $format;
 
-    function __construct($errorcorrectionlevel = 'L', $bgcolor = 'ffffff', $color = '000000', $format = 'p') 
+    /**
+     * @param string $errorcorrectionlevel
+     * @param string $bgcolor
+     * @param string $color
+     * @param string $format
+     */
+    public function __construct($errorcorrectionlevel = 'L', $bgcolor = 'ffffff', $color = '000000', $format = 'p')
     {
         $this->verifyssl = false;
-        
+
         $this->errorcorrectionlevel = $errorcorrectionlevel;
         $this->bgcolor = $bgcolor;
         $this->color = $color;
         $this->format = $format;
     }
-    
-    public function getMimeType() 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimeType()
     {
-        switch (strtolower($this->format))
-        {
-        	case 'p':
+        switch (strtolower($this->format)) {
+            case 'p':
                 return 'image/png';
-        	case 'g':
+            case 'g':
                 return 'image/gif';
-        	case 'j':
+            case 'j':
                 return 'image/jpeg';
         }
-        throw new \QRException(sprintf('Unknown MIME-type: %s', $this->format));
+        throw new QRException(sprintf('Unknown MIME-type: %s', $this->format));
     }
-    
-    public function getQRCodeImage($qrtext, $size) 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getQRCodeImage($qrtext, $size)
     {
         return $this->getContent($this->getUrl($qrtext, $size));
     }
-    
-    public function getUrl($qrtext, $size) 
+
+    /**
+     * @param string $qrtext the value to encode in the QR code
+     * @param int|string $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
+    public function getUrl($qrtext, $size)
     {
         return 'http://qrickit.com/api/qr'
             . '?qrsize=' . $size
@@ -51,4 +73,4 @@
             . '&t=' . strtolower($this->format)
             . '&d=' . rawurlencode($qrtext);
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php
index 8dba7fc..088edab 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php
@@ -4,11 +4,19 @@
 
 class CSRNGProvider implements IRNGProvider
 {
-    public function getRandomBytes($bytecount) {
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
         return random_bytes($bytecount);    // PHP7+
     }
-    
-    public function isCryptographicallySecure() {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
         return true;
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php
index eb42577..d17a5f8 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php
@@ -1,28 +1,43 @@
 <?php
+
 namespace RobThree\Auth\Providers\Rng;
 
 class HashRNGProvider implements IRNGProvider
 {
+    /** @var string */
     private $algorithm;
-    
-    function __construct($algorithm = 'sha256' ) {
+
+    /**
+     * @param string $algorithm
+     */
+    public function __construct($algorithm = 'sha256')
+    {
         $algos = array_values(hash_algos());
-        if (!in_array($algorithm, $algos, true))
-            throw new \RNGException('Unsupported algorithm specified');
+        if (!in_array($algorithm, $algos, true)) {
+            throw new RNGException('Unsupported algorithm specified');
+        }
         $this->algorithm = $algorithm;
     }
-    
-    public function getRandomBytes($bytecount) {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
         $result = '';
         $hash = mt_rand();
         for ($i = 0; $i < $bytecount; $i++) {
-            $hash = hash($this->algorithm, $hash.mt_rand(), true);
-            $result .= $hash[mt_rand(0, strlen($hash)-1)];
+            $hash = hash($this->algorithm, $hash . mt_rand(), true);
+            $result .= $hash[mt_rand(0, strlen($hash) - 1)];
         }
         return $result;
     }
-    
-    public function isCryptographicallySecure() {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
         return false;
     }
 }
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php
index 6be2800..e4e71c2 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php
@@ -4,6 +4,15 @@
 
 interface IRNGProvider
 {
+    /**
+     * @param int $bytecount the number of bytes of randomness to return
+     *
+     * @return string the random bytes
+     */
     public function getRandomBytes($bytecount);
+
+    /**
+     * @return bool whether this provider is cryptographically secure
+     */
     public function isCryptographicallySecure();
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php
index 0eeab2c..d1b6430 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php
@@ -4,20 +4,34 @@
 
 class MCryptRNGProvider implements IRNGProvider
 {
+    /** @var int */
     private $source;
-    
-    function __construct($source = MCRYPT_DEV_URANDOM) {
+
+    /**
+     * @param int $source
+     */
+    public function __construct($source = MCRYPT_DEV_URANDOM)
+    {
         $this->source = $source;
     }
-    
-    public function getRandomBytes($bytecount) {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
         $result = @mcrypt_create_iv($bytecount, $this->source);
-        if ($result === false)
-            throw new \RNGException('mcrypt_create_iv returned an invalid value');
+        if ($result === false) {
+            throw new RNGException('mcrypt_create_iv returned an invalid value');
+        }
         return $result;
     }
-    
-    public function isCryptographicallySecure() {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
         return true;
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php
index dc66c64..eb82b3b 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php
@@ -4,22 +4,37 @@
 
 class OpenSSLRNGProvider implements IRNGProvider
 {
+    /** @var bool */
     private $requirestrong;
-    
-    function __construct($requirestrong = true) {
+
+    /**
+     * @param bool $requirestrong
+     */
+    public function __construct($requirestrong = true)
+    {
         $this->requirestrong = $requirestrong;
     }
-    
-    public function getRandomBytes($bytecount) {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
         $result = openssl_random_pseudo_bytes($bytecount, $crypto_strong);
-        if ($this->requirestrong && ($crypto_strong === false))
-            throw new \RNGException('openssl_random_pseudo_bytes returned non-cryptographically strong value');
-        if ($result === false)
-            throw new \RNGException('openssl_random_pseudo_bytes returned an invalid value');
+        if ($this->requirestrong && ($crypto_strong === false)) {
+            throw new RNGException('openssl_random_pseudo_bytes returned non-cryptographically strong value');
+        }
+        if ($result === false) {
+            throw new RNGException('openssl_random_pseudo_bytes returned an invalid value');
+        }
         return $result;
     }
-    
-    public function isCryptographicallySecure() {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
         return $this->requirestrong;
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php
index eb5e913..f9a11ac 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace RobThree\Auth\Providers\Rng;
+
 use RobThree\Auth\TwoFactorAuthException;
 
-class RNGException extends TwoFactorAuthException {}
\ No newline at end of file
+class RNGException extends TwoFactorAuthException {}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php
index 8e7806e..c346e5a 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php
@@ -2,22 +2,33 @@
 
 namespace RobThree\Auth\Providers\Time;
 
+use DateTime;
+
 /**
  * Takes the time from any webserver by doing a HEAD request on the specified URL and extracting the 'Date:' header
  */
 class HttpTimeProvider implements ITimeProvider
 {
+    /** @var string */
     public $url;
-    public $options;
+
+    /** @var string */
     public $expectedtimeformat;
 
-    function __construct($url = 'https://google.com', $expectedtimeformat = 'D, d M Y H:i:s O+', array $options = null)
+    /** @var array */
+    public $options;
+
+    /**
+     * @param string $url
+     * @param string $expectedtimeformat
+     * @param array $options
+     */
+    public function __construct($url = 'https://google.com', $expectedtimeformat = 'D, d M Y H:i:s O+', array $options = null)
     {
         $this->url = $url;
         $this->expectedtimeformat = $expectedtimeformat;
-        $this->options = $options;
-        if ($this->options === null) {
-            $this->options = array(
+        if ($options === null) {
+            $options = array(
                 'http' => array(
                     'method' => 'HEAD',
                     'follow_location' => false,
@@ -32,9 +43,14 @@
                 )
             );
         }
+        $this->options = $options;
     }
 
-    public function getTime() {
+    /**
+     * {@inheritdoc}
+     */
+    public function getTime()
+    {
         try {
             $context  = stream_context_create($this->options);
             $fd = fopen($this->url, 'rb', false, $context);
@@ -42,13 +58,14 @@
             fclose($fd);
 
             foreach ($headers['wrapper_data'] as $h) {
-                if (strcasecmp(substr($h, 0, 5), 'Date:') === 0)
-                    return \DateTime::createFromFormat($this->expectedtimeformat, trim(substr($h,5)))->getTimestamp();
+                if (strcasecmp(substr($h, 0, 5), 'Date:') === 0) {
+                    return DateTime::createFromFormat($this->expectedtimeformat, trim(substr($h, 5)))->getTimestamp();
+                }
             }
-            throw new \TimeException(sprintf('Unable to retrieve time from %s (Invalid or no "Date:" header found)', $this->url));
+            throw new \Exception('Invalid or no "Date:" header found');
+        } catch (\Exception $ex) {
+            throw new TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->url, $ex->getMessage()));
         }
-        catch (Exception $ex) {
-            throw new \TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->url, $ex->getMessage()));
-        }
+
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php
index a3b87a2..4799f17 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php
@@ -4,5 +4,8 @@
 
 interface ITimeProvider
 {
+    /**
+     * @return int the current timestamp according to this provider
+     */
     public function getTime();
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/LocalMachineTimeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/LocalMachineTimeProvider.php
index 572cedc..2fe6846 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/LocalMachineTimeProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/LocalMachineTimeProvider.php
@@ -2,8 +2,10 @@
 
 namespace RobThree\Auth\Providers\Time;
 
-class LocalMachineTimeProvider implements ITimeProvider {
-    public function getTime() {
+class LocalMachineTimeProvider implements ITimeProvider
+{
+    public function getTime()
+    {
         return time();
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php
index d69a3a6..a701850 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php
@@ -7,24 +7,40 @@
  */
 class NTPTimeProvider implements ITimeProvider
 {
+    /** @var string */
     public $host;
+
+    /** @var int */
     public $port;
+
+    /** @var int */
     public $timeout;
 
-    function __construct($host = 'time.google.com', $port = 123, $timeout = 1)
+    /**
+     * @param string $host
+     * @param int $port
+     * @param int $timeout
+     */
+    public function __construct($host = 'time.google.com', $port = 123, $timeout = 1)
     {
         $this->host = $host;
 
-        if (!is_int($port) || $port <= 0 || $port > 65535)
-            throw new \TimeException('Port must be 0 < port < 65535');
+        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');
+        if (!is_int($timeout) || $timeout < 0) {
+            throw new TimeException('Timeout must be >= 0');
+        }
         $this->timeout = $timeout;
     }
 
-    public function getTime() {
+    /**
+     * {@inheritdoc}
+     */
+    public function getTime()
+    {
         try {
             /* Create a socket and connect to NTP server */
             $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
@@ -36,19 +52,19 @@
             socket_send($sock, $msg, strlen($msg), 0);
 
             /* Receive response and close socket */
-            if (socket_recv($sock, $recv, 48, MSG_WAITALL) === false)
+            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]);
+            $timestamp = (int) 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()));
+        } catch (\Exception $ex) {
+            throw new TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->host, $ex->getMessage()));
         }
     }
 }
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/TimeException.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/TimeException.php
index 8de544d..c5a06e2 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/TimeException.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/TimeException.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace RobThree\Auth\Providers\Time;
+
 use RobThree\Auth\TwoFactorAuthException;
 
-class TimeException extends TwoFactorAuthException {}
\ No newline at end of file
+class TimeException extends TwoFactorAuthException {}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php
index 7bc067d..c46ac17 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php
@@ -1,40 +1,82 @@
 <?php
+
 namespace RobThree\Auth;
 
 use RobThree\Auth\Providers\Qr\IQRCodeProvider;
+use RobThree\Auth\Providers\Qr\QRServerProvider;
+use RobThree\Auth\Providers\Rng\CSRNGProvider;
+use RobThree\Auth\Providers\Rng\HashRNGProvider;
 use RobThree\Auth\Providers\Rng\IRNGProvider;
+use RobThree\Auth\Providers\Rng\MCryptRNGProvider;
+use RobThree\Auth\Providers\Rng\OpenSSLRNGProvider;
+use RobThree\Auth\Providers\Time\HttpTimeProvider;
 use RobThree\Auth\Providers\Time\ITimeProvider;
+use RobThree\Auth\Providers\Time\LocalMachineTimeProvider;
+use RobThree\Auth\Providers\Time\NTPTimeProvider;
 
 // Based on / inspired by: https://github.com/PHPGangsta/GoogleAuthenticator
 // Algorithms, digits, period etc. explained: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
 class TwoFactorAuth
 {
+    /** @var string */
     private $algorithm;
+
+    /** @var int */
     private $period;
+
+    /** @var int */
     private $digits;
+
+    /** @var string */
     private $issuer;
+
+    /** @var ?IQRCodeProvider */
     private $qrcodeprovider = null;
+
+    /** @var ?IRNGProvider */
     private $rngprovider = null;
+
+    /** @var ?ITimeProvider */
     private $timeprovider = null;
+
+    /** @var string */
     private static $_base32dict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=';
+
+    /** @var array */
     private static $_base32;
+
+    /** @var array */
     private static $_base32lookup = array();
+
+    /** @var array */
     private static $_supportedalgos = array('sha1', 'sha256', 'sha512', 'md5');
 
-    function __construct($issuer = null, $digits = 6, $period = 30, $algorithm = 'sha1', IQRCodeProvider $qrcodeprovider = null, IRNGProvider $rngprovider = null, ITimeProvider $timeprovider = null)
+    /**
+     * @param ?string $issuer
+     * @param int $digits
+     * @param int $period
+     * @param string $algorithm
+     * @param ?IQRCodeProvider $qrcodeprovider
+     * @param ?IRNGProvider $rngprovider
+     * @param ?ITimeProvider $timeprovider
+     */
+    public function __construct($issuer = null, $digits = 6, $period = 30, $algorithm = 'sha1', IQRCodeProvider $qrcodeprovider = null, IRNGProvider $rngprovider = null, ITimeProvider $timeprovider = null)
     {
         $this->issuer = $issuer;
-        if (!is_int($digits) || $digits <= 0)
+        if (!is_int($digits) || $digits <= 0) {
             throw new TwoFactorAuthException('Digits must be int > 0');
+        }
         $this->digits = $digits;
 
-        if (!is_int($period) || $period <= 0)
+        if (!is_int($period) || $period <= 0) {
             throw new TwoFactorAuthException('Period must be int > 0');
+        }
         $this->period = $period;
 
         $algorithm = strtolower(trim($algorithm));
-        if (!in_array($algorithm, self::$_supportedalgos))
+        if (!in_array($algorithm, self::$_supportedalgos)) {
             throw new TwoFactorAuthException('Unsupported algorithm: ' . $algorithm);
+        }
         $this->algorithm = $algorithm;
         $this->qrcodeprovider = $qrcodeprovider;
         $this->rngprovider = $rngprovider;
@@ -46,22 +88,34 @@
 
     /**
      * Create a new secret
+     *
+     * @param int $bits
+     * @param bool $requirecryptosecure
+     *
+     * @return string
      */
     public function createSecret($bits = 80, $requirecryptosecure = true)
     {
         $secret = '';
-        $bytes = ceil($bits / 5);   //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32)
-        $rngprovider = $this->getRngprovider();
-        if ($requirecryptosecure && !$rngprovider->isCryptographicallySecure())
+        $bytes = (int) ceil($bits / 5);   //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32)
+        $rngprovider = $this->getRngProvider();
+        if ($requirecryptosecure && !$rngprovider->isCryptographicallySecure()) {
             throw new TwoFactorAuthException('RNG provider is not cryptographically secure');
+        }
         $rnd = $rngprovider->getRandomBytes($bytes);
-        for ($i = 0; $i < $bytes; $i++)
+        for ($i = 0; $i < $bytes; $i++) {
             $secret .= self::$_base32[ord($rnd[$i]) & 31];  //Mask out left 3 bits for 0-31 values
+        }
         return $secret;
     }
 
     /**
      * Calculate the code with given secret and point in time
+     *
+     * @param string $secret
+     * @param ?int $time
+     *
+     * @return string
      */
     public function getCode($secret, $time = null)
     {
@@ -73,15 +127,23 @@
         $value = unpack('N', $hashpart);                                                   // Unpack binary value
         $value = $value[1] & 0x7FFFFFFF;                                                   // Drop MSB, keep only 31 bits
 
-        return str_pad($value % pow(10, $this->digits), $this->digits, '0', STR_PAD_LEFT);
+        return str_pad((string) ($value % pow(10, $this->digits)), $this->digits, '0', STR_PAD_LEFT);
     }
 
     /**
      * Check if the code is correct. This will accept codes starting from ($discrepancy * $period) sec ago to ($discrepancy * period) sec from now
+     *
+     * @param string $secret
+     * @param string $code
+     * @param int $discrepancy
+     * @param ?int $time
+     * @param int $timeslice
+     *
+     * @return bool
      */
     public function verifyCode($secret, $code, $discrepancy = 1, $time = null, &$timeslice = 0)
     {
-        $timetamp = $this->getTime($time);
+        $timestamp = $this->getTime($time);
 
         $timeslice = 0;
 
@@ -90,7 +152,7 @@
         // 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);
+            $ts = $timestamp + ($i * $this->period);
             $slice = $this->getTimeSlice($ts);
             $timeslice = $this->codeEquals($this->getCode($secret, $ts), $code) ? $slice : $timeslice;
         }
@@ -100,17 +162,24 @@
 
     /**
      * Timing-attack safe comparison of 2 codes (see http://blog.ircmaxell.com/2014/11/its-all-about-time.html)
+     *
+     * @param string $safe
+     * @param string $user
+     *
+     * @return bool
      */
-    private function codeEquals($safe, $user) {
+    private function codeEquals($safe, $user)
+    {
         if (function_exists('hash_equals')) {
             return hash_equals($safe, $user);
         }
         // In general, it's not possible to prevent length leaks. So it's OK to leak the length. The important part is that
         // we don't leak information about the difference of the two strings.
-        if (strlen($safe)===strlen($user)) {
+        if (strlen($safe) === strlen($user)) {
             $result = 0;
-            for ($i = 0; $i < strlen($safe); $i++)
+            for ($i = 0; $i < strlen($safe); $i++) {
                 $result |= (ord($safe[$i]) ^ ord($user[$i]));
+            }
             return $result === 0;
         }
         return false;
@@ -118,11 +187,18 @@
 
     /**
      * Get data-uri of QRCode
+     *
+     * @param string $label
+     * @param string $secret
+     * @param mixed $size
+     *
+     * @return string
      */
     public function getQRCodeImageAsDataUri($label, $secret, $size = 200)
     {
-        if (!is_int($size) || $size <= 0)
+        if (!is_int($size) || $size <= 0) {
             throw new TwoFactorAuthException('Size must be int > 0');
+        }
 
         $qrcodeprovider = $this->getQrCodeProvider();
         return 'data:'
@@ -133,37 +209,52 @@
 
     /**
      * Compare default timeprovider with specified timeproviders and ensure the time is within the specified number of seconds (leniency)
+     * @param ?array $timeproviders
+     * @param int $leniency
+     *
+     * @return void
      */
     public function ensureCorrectTime(array $timeproviders = null, $leniency = 5)
     {
-        if ($timeproviders != null && !is_array($timeproviders))
-            throw new TwoFactorAuthException('No timeproviders specified');
-
-        if ($timeproviders == null)
+        if ($timeproviders === null) {
             $timeproviders = array(
-                new Providers\Time\NTPTimeProvider(),
-                new Providers\Time\HttpTimeProvider()
+                new NTPTimeProvider(),
+                new HttpTimeProvider()
             );
+        }
 
         // Get default time provider
         $timeprovider = $this->getTimeProvider();
 
         // Iterate specified time providers
         foreach ($timeproviders as $t) {
-            if (!($t instanceof ITimeProvider))
+            if (!($t instanceof ITimeProvider)) {
                 throw new TwoFactorAuthException('Object does not implement ITimeProvider');
+            }
 
             // Get time from default time provider and compare to specific time provider and throw if time difference is more than specified number of seconds leniency
-            if (abs($timeprovider->getTime() - $t->getTime()) > $leniency)
+            if (abs($timeprovider->getTime() - $t->getTime()) > $leniency) {
                 throw new TwoFactorAuthException(sprintf('Time for timeprovider is off by more than %d seconds when compared to %s', $leniency, get_class($t)));
+            }
         }
     }
 
-    private function getTime($time)
+    /**
+     * @param ?int $time
+     *
+     * @return int
+     */
+    private function getTime($time = null)
     {
         return ($time === null) ? $this->getTimeProvider()->getTime() : $time;
     }
 
+    /**
+     * @param int $time
+     * @param int $offset
+     *
+     * @return int
+     */
     private function getTimeSlice($time = null, $offset = 0)
     {
         return (int)floor($time / $this->period) + ($offset * $this->period);
@@ -171,6 +262,11 @@
 
     /**
      * Builds a string to be encoded in a QR code
+     *
+     * @param string $label
+     * @param string $secret
+     *
+     * @return string
      */
     public function getQRText($label, $secret)
     {
@@ -182,25 +278,33 @@
             . '&digits=' . intval($this->digits);
     }
 
+    /**
+     * @param string $value
+     * @return string
+     */
     private function base32Decode($value)
     {
-        if (strlen($value)==0) return '';
+        if (strlen($value) == 0) {
+            return '';
+        }
 
-        if (preg_match('/[^'.preg_quote(self::$_base32dict).']/', $value) !== 0)
+        if (preg_match('/[^' . preg_quote(self::$_base32dict) . ']/', $value) !== 0) {
             throw new TwoFactorAuthException('Invalid base32 string');
+        }
 
         $buffer = '';
-        foreach (str_split($value) as $char)
-        {
-            if ($char !== '=')
-                $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, 0, STR_PAD_LEFT);
+        foreach (str_split($value) as $char) {
+            if ($char !== '=') {
+                $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, '0', STR_PAD_LEFT);
+            }
         }
         $length = strlen($buffer);
         $blocks = trim(chunk_split(substr($buffer, 0, $length - ($length % 8)), 8, ' '));
 
         $output = '';
-        foreach (explode(' ', $blocks) as $block)
-            $output .= chr(bindec(str_pad($block, 8, 0, STR_PAD_RIGHT)));
+        foreach (explode(' ', $blocks) as $block) {
+            $output .= chr(bindec(str_pad($block, 8, '0', STR_PAD_RIGHT)));
+        }
         return $output;
     }
 
@@ -212,7 +316,7 @@
     {
         // Set default QR Code provider if none was specified
         if (null === $this->qrcodeprovider) {
-            return $this->qrcodeprovider = new Providers\Qr\QRServerProvider();
+            return $this->qrcodeprovider = new QRServerProvider();
         }
         return $this->qrcodeprovider;
     }
@@ -221,22 +325,22 @@
      * @return IRNGProvider
      * @throws TwoFactorAuthException
      */
-    public function getRngprovider()
+    public function getRngProvider()
     {
         if (null !== $this->rngprovider) {
             return $this->rngprovider;
         }
         if (function_exists('random_bytes')) {
-            return $this->rngprovider = new Providers\Rng\CSRNGProvider();
+            return $this->rngprovider = new CSRNGProvider();
         }
         if (function_exists('mcrypt_create_iv')) {
-            return $this->rngprovider = new Providers\Rng\MCryptRNGProvider();
+            return $this->rngprovider = new MCryptRNGProvider();
         }
         if (function_exists('openssl_random_pseudo_bytes')) {
-            return $this->rngprovider = new Providers\Rng\OpenSSLRNGProvider();
+            return $this->rngprovider = new OpenSSLRNGProvider();
         }
         if (function_exists('hash')) {
-            return $this->rngprovider = new Providers\Rng\HashRNGProvider();
+            return $this->rngprovider = new HashRNGProvider();
         }
         throw new TwoFactorAuthException('Unable to find a suited RNGProvider');
     }
@@ -249,8 +353,8 @@
     {
         // Set default time provider if none was specified
         if (null === $this->timeprovider) {
-            return $this->timeprovider = new Providers\Time\LocalMachineTimeProvider();
+            return $this->timeprovider = new LocalMachineTimeProvider();
         }
         return $this->timeprovider;
     }
-}
\ No newline at end of file
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php
index af51b74..bce8370 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php
@@ -4,4 +4,4 @@
 
 use Exception;
 
-class TwoFactorAuthException extends \Exception {}
\ No newline at end of file
+class TwoFactorAuthException extends Exception {}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml
index 92c3a27..b2ff004 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <phpunit backupGlobals="false"
          backupStaticAttributes="false"
          colors="true"
@@ -6,15 +6,21 @@
          convertNoticesToExceptions="true"
          convertWarningsToExceptions="true"
          processIsolation="false"
+         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          stopOnFailure="false">
   <testsuites>
     <testsuite name="Unit">
       <directory suffix="Test.php">./tests</directory>
     </testsuite>
   </testsuites>
-  <filter>
-    <whitelist processUncoveredFilesFromWhitelist="true">
+  <coverage processUncoveredFiles="true">
+    <include>
       <directory suffix=".php">./lib</directory>
-    </whitelist>
-  </filter>
-</phpunit>
\ No newline at end of file
+    </include>
+    <report>
+      <html outputDirectory="build/coverage"/>
+      <text outputFile="php://stdout"/>
+    </report>
+  </coverage>
+</phpunit>
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml.tmppica b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml.tmppica
deleted file mode 100644
index e69de29..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml.tmppica
+++ /dev/null
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/MightNotMakeAssertions.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/MightNotMakeAssertions.php
new file mode 100644
index 0000000..a7fbded
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/MightNotMakeAssertions.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Tests;
+
+trait MightNotMakeAssertions
+{
+    /**
+     * This is a shim to support PHPUnit for php 5.6 and 7.0.
+     *
+     * It has to be named something that doesn't collide with existing
+     * TestCase methods as we can't support PHP return types right now
+     *
+     * @return void
+     */
+    public function noAssertionsMade()
+    {
+        foreach (class_parents($this) as $parent) {
+            if (method_exists($parent, 'expectNotToPerformAssertions')) {
+                parent::expectNotToPerformAssertions();
+                return;
+            }
+        }
+
+        $this->assertTrue(true);
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Qr/IQRCodeProviderTest.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Qr/IQRCodeProviderTest.php
new file mode 100644
index 0000000..86dd431
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Qr/IQRCodeProviderTest.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Tests\Providers\Qr;
+
+use PHPUnit\Framework\TestCase;
+use RobThree\Auth\TwoFactorAuth;
+use RobThree\Auth\TwoFactorAuthException;
+
+class IQRCodeProviderTest extends TestCase
+{
+    /**
+     * @param string $datauri
+     *
+     * @return null|array
+     */
+    private function DecodeDataUri($datauri)
+    {
+        if (preg_match('/data:(?P<mimetype>[\w\.\-\/]+);(?P<encoding>\w+),(?P<data>.*)/', $datauri, $m) === 1) {
+            return array(
+                'mimetype' => $m['mimetype'],
+                'encoding' => $m['encoding'],
+                'data' => base64_decode($m['data'])
+            );
+        }
+
+        return null;
+    }
+
+    /**
+     * @return void
+     */
+    public function testTotpUriIsCorrect()
+    {
+        $qr = new TestQrProvider();
+
+        $tfa = new TwoFactorAuth('Test&Issuer', 6, 30, 'sha1', $qr);
+        $data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
+        $this->assertEquals('test/test', $data['mimetype']);
+        $this->assertEquals('base64', $data['encoding']);
+        $this->assertEquals('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=Test%26Issuer&period=30&algorithm=SHA1&digits=6@200', $data['data']);
+    }
+
+    /**
+     * @return void
+     */
+    public function testGetQRCodeImageAsDataUriThrowsOnInvalidSize()
+    {
+        $qr = new TestQrProvider();
+
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', $qr);
+
+        $this->expectException(TwoFactorAuthException::class);
+
+        $tfa->getQRCodeImageAsDataUri('Test', 'VMR466AB62ZBOKHE', 0);
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Qr/TestQrProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Qr/TestQrProvider.php
new file mode 100644
index 0000000..93242c2
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Qr/TestQrProvider.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Tests\Providers\Qr;
+
+use RobThree\Auth\Providers\Qr\IQRCodeProvider;
+
+class TestQrProvider implements IQRCodeProvider
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getQRCodeImage($qrtext, $size)
+    {
+        return $qrtext . '@' . $size;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimeType()
+    {
+        return 'test/test';
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/CSRNGProviderTest.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/CSRNGProviderTest.php
new file mode 100644
index 0000000..e42ccfd
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/CSRNGProviderTest.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Tests\Providers\Rng;
+
+use PHPUnit\Framework\TestCase;
+use Tests\MightNotMakeAssertions;
+use RobThree\Auth\Providers\Rng\CSRNGProvider;
+
+class CSRNGProviderTest extends TestCase
+{
+    use NeedsRngLengths, MightNotMakeAssertions;
+
+    /**
+     * @requires function random_bytes
+     *
+     * @return void
+     */
+    public function testCSRNGProvidersReturnExpectedNumberOfBytes()
+    {
+        if (function_exists('random_bytes')) {
+            $rng = new CSRNGProvider();
+            foreach ($this->rngTestLengths as $l) {
+                $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
+            }
+            $this->assertTrue($rng->isCryptographicallySecure());
+        } else {
+            $this->noAssertionsMade();
+        }
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/HashRNGProviderTest.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/HashRNGProviderTest.php
new file mode 100644
index 0000000..c99879d
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/HashRNGProviderTest.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Tests\Providers\Rng;
+
+use PHPUnit\Framework\TestCase;
+use RobThree\Auth\Providers\Rng\HashRNGProvider;
+
+class HashRNGProviderTest extends TestCase
+{
+    use NeedsRngLengths;
+
+    /**
+     * @return void
+     */
+    public function testHashRNGProvidersReturnExpectedNumberOfBytes()
+    {
+        $rng = new HashRNGProvider();
+        foreach ($this->rngTestLengths as $l) {
+            $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
+        }
+
+        $this->assertFalse($rng->isCryptographicallySecure());
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/IRNGProviderTest.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/IRNGProviderTest.php
new file mode 100644
index 0000000..8897673
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/IRNGProviderTest.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Tests\Providers\Rng;
+
+use PHPUnit\Framework\TestCase;
+use RobThree\Auth\TwoFactorAuth;
+use RobThree\Auth\TwoFactorAuthException;
+
+class IRNGProviderTest extends TestCase
+{
+    /**
+     * @return void
+     */
+    public function testCreateSecretThrowsOnInsecureRNGProvider()
+    {
+        $rng = new TestRNGProvider();
+
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng);
+
+        $this->expectException(TwoFactorAuthException::class);
+        $tfa->createSecret();
+    }
+
+    /**
+     * @return void
+     */
+    public function testCreateSecretOverrideSecureDoesNotThrowOnInsecureRNG()
+    {
+        $rng = new TestRNGProvider();
+
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng);
+        $this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret(80, false));
+    }
+
+    /**
+     * @return void
+     */
+    public function testCreateSecretDoesNotThrowOnSecureRNGProvider()
+    {
+        $rng = new TestRNGProvider(true);
+
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng);
+        $this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret());
+    }
+
+    /**
+     * @return void
+     */
+    public function testCreateSecretGeneratesDesiredAmountOfEntropy()
+    {
+        $rng = new TestRNGProvider(true);
+
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng);
+        $this->assertEquals('A', $tfa->createSecret(5));
+        $this->assertEquals('AB', $tfa->createSecret(6));
+        $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $tfa->createSecret(128));
+        $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', $tfa->createSecret(160));
+        $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', $tfa->createSecret(320));
+        $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567A', $tfa->createSecret(321));
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/MCryptRNGProviderTest.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/MCryptRNGProviderTest.php
new file mode 100644
index 0000000..f6dd91e
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/MCryptRNGProviderTest.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Tests\Providers\Rng;
+
+use PHPUnit\Framework\TestCase;
+use Tests\MightNotMakeAssertions;
+use RobThree\Auth\Providers\Rng\MCryptRNGProvider;
+
+class MCryptRNGProviderTest extends TestCase
+{
+    use NeedsRngLengths, MightNotMakeAssertions;
+
+    /**
+     * @requires function mcrypt_create_iv
+     *
+     * @return void
+     */
+    public function testMCryptRNGProvidersReturnExpectedNumberOfBytes()
+    {
+        if (function_exists('mcrypt_create_iv')) {
+            $rng = new MCryptRNGProvider();
+
+            foreach ($this->rngTestLengths as $l) {
+                $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
+            }
+
+            $this->assertTrue($rng->isCryptographicallySecure());
+        } else {
+            $this->noAssertionsMade();
+        }
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/NeedsRngLengths.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/NeedsRngLengths.php
new file mode 100644
index 0000000..7bbfed9
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/NeedsRngLengths.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Tests\Providers\Rng;
+
+trait NeedsRngLengths
+{
+    /** @var array */
+    protected $rngTestLengths = array(1, 16, 32, 256);
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/OpenSSLRNGProviderTest.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/OpenSSLRNGProviderTest.php
new file mode 100644
index 0000000..c941fcc
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/OpenSSLRNGProviderTest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Tests\Providers\Rng;
+
+use PHPUnit\Framework\TestCase;
+use RobThree\Auth\Providers\Rng\OpenSSLRNGProvider;
+
+class OpenSSLRNGProviderTest extends TestCase
+{
+    use NeedsRngLengths;
+
+    /**
+     * @return void
+     */
+    public function testStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes()
+    {
+        $rng = new OpenSSLRNGProvider(true);
+        foreach ($this->rngTestLengths as $l) {
+            $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
+        }
+
+        $this->assertTrue($rng->isCryptographicallySecure());
+    }
+
+    /**
+     * @return void
+     */
+    public function testNonStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes()
+    {
+        $rng = new OpenSSLRNGProvider(false);
+        foreach ($this->rngTestLengths as $l) {
+            $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
+        }
+
+        $this->assertFalse($rng->isCryptographicallySecure());
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/TestRNGProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/TestRNGProvider.php
new file mode 100644
index 0000000..7179521
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Rng/TestRNGProvider.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Tests\Providers\Rng;
+
+use RobThree\Auth\Providers\Rng\IRNGProvider;
+
+class TestRNGProvider implements IRNGProvider
+{
+    /** @var bool */
+    private $isSecure;
+
+    /**
+     * @param bool $isSecure whether this provider is cryptographically secure
+     */
+    function __construct($isSecure = false)
+    {
+        $this->isSecure = $isSecure;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
+        $result = '';
+
+        for ($i = 0; $i < $bytecount; $i++) {
+            $result .= chr($i);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
+        return $this->isSecure;
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Time/ITimeProviderTest.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Time/ITimeProviderTest.php
new file mode 100644
index 0000000..159e0c8
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Time/ITimeProviderTest.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Tests\Providers\Time;
+
+use PHPUnit\Framework\TestCase;
+use Tests\MightNotMakeAssertions;
+use RobThree\Auth\TwoFactorAuthException;
+use RobThree\Auth\TwoFactorAuth;
+
+class ITimeProviderTest extends TestCase
+{
+    use MightNotMakeAssertions;
+
+    /**
+     * @return void
+     */
+    public function testEnsureCorrectTimeDoesNotThrowForCorrectTime()
+    {
+        $tpr1 = new TestTimeProvider(123);
+        $tpr2 = new TestTimeProvider(128);
+
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, null, $tpr1);
+        $tfa->ensureCorrectTime(array($tpr2));   // 128 - 123 = 5 => within default leniency
+
+        $this->noAssertionsMade();
+    }
+
+    /**
+     * @return void
+     */
+    public function testEnsureCorrectTimeThrowsOnIncorrectTime()
+    {
+        $tpr1 = new TestTimeProvider(123);
+        $tpr2 = new TestTimeProvider(124);
+
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, null, $tpr1);
+
+        $this->expectException(TwoFactorAuthException::class);
+
+        $tfa->ensureCorrectTime(array($tpr2), 0);    // We force a leniency of 0, 124-123 = 1 so this should throw
+    }
+
+    /**
+     * @return void
+     */
+    public function testEnsureDefaultTimeProviderReturnsCorrectTime()
+    {
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1');
+        $tfa->ensureCorrectTime(array(new TestTimeProvider(time())), 1);    // Use a leniency of 1, should the time change between both time() calls
+
+        $this->noAssertionsMade();
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Time/TestTimeProvider.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Time/TestTimeProvider.php
new file mode 100644
index 0000000..0fc2d12
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/Providers/Time/TestTimeProvider.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Tests\Providers\Time;
+
+use RobThree\Auth\Providers\Time\ITimeProvider;
+
+class TestTimeProvider implements ITimeProvider
+{
+    /** @var int */
+    private $time;
+
+    /**
+     * @param int $time
+     */
+    function __construct($time)
+    {
+        $this->time = $time;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTime()
+    {
+        return $this->time;
+    }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php
index a0f2f67..ca00df9 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/lib/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php
@@ -1,218 +1,151 @@
 <?php
-require_once 'lib/TwoFactorAuth.php';
-require_once 'lib/TwoFactorAuthException.php';
 
-require_once 'lib/Providers/Qr/IQRCodeProvider.php';
-require_once 'lib/Providers/Qr/BaseHTTPQRCodeProvider.php';
-require_once 'lib/Providers/Qr/ImageChartsQRCodeProvider.php';
-require_once 'lib/Providers/Qr/QRException.php';
+namespace Tests;
 
-require_once 'lib/Providers/Rng/IRNGProvider.php';
-require_once 'lib/Providers/Rng/RNGException.php';
-require_once 'lib/Providers/Rng/CSRNGProvider.php';
-require_once 'lib/Providers/Rng/MCryptRNGProvider.php';
-require_once 'lib/Providers/Rng/OpenSSLRNGProvider.php';
-require_once 'lib/Providers/Rng/HashRNGProvider.php';
-require_once 'lib/Providers/Rng/RNGException.php';
-
-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/NTPTimeProvider.php';
-require_once 'lib/Providers/Time/TimeException.php';
-
+use PHPUnit\Framework\TestCase;
+use RobThree\Auth\TwoFactorAuthException;
 use RobThree\Auth\TwoFactorAuth;
-use RobThree\Auth\Providers\Qr\IQRCodeProvider;
-use RobThree\Auth\Providers\Rng\IRNGProvider;
-use RobThree\Auth\Providers\Time\ITimeProvider;
 
-
-class TwoFactorAuthTest extends PHPUnit_Framework_TestCase
+class TwoFactorAuthTest extends TestCase
 {
+    use MightNotMakeAssertions;
+
     /**
-     * @expectedException \RobThree\Auth\TwoFactorAuthException
+     * @return void
      */
-    public function testConstructorThrowsOnInvalidDigits() {
+    public function testConstructorThrowsOnInvalidDigits()
+    {
+        $this->expectException(TwoFactorAuthException::class);
 
         new TwoFactorAuth('Test', 0);
     }
 
     /**
-     * @expectedException \RobThree\Auth\TwoFactorAuthException
+     * @return void
      */
-    public function testConstructorThrowsOnInvalidPeriod() {
+    public function testConstructorThrowsOnInvalidPeriod()
+    {
+        $this->expectException(TwoFactorAuthException::class);
 
         new TwoFactorAuth('Test', 6, 0);
     }
 
     /**
-     * @expectedException \RobThree\Auth\TwoFactorAuthException
+     * @return void
      */
-    public function testConstructorThrowsOnInvalidAlgorithm() {
+    public function testConstructorThrowsOnInvalidAlgorithm()
+    {
+        $this->expectException(TwoFactorAuthException::class);
 
         new TwoFactorAuth('Test', 6, 30, 'xxx');
     }
 
-    public function testGetCodeReturnsCorrectResults() {
-
+    /**
+     * @return void
+     */
+    public function testGetCodeReturnsCorrectResults()
+    {
         $tfa = new TwoFactorAuth('Test');
         $this->assertEquals('543160', $tfa->getCode('VMR466AB62ZBOKHE', 1426847216));
         $this->assertEquals('538532', $tfa->getCode('VMR466AB62ZBOKHE', 0));
     }
 
     /**
-     * @expectedException \RobThree\Auth\TwoFactorAuthException
+     * @return void
      */
-    public function testCreateSecretThrowsOnInsecureRNGProvider() {
-        $rng = new TestRNGProvider();
-
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng);
-        $tfa->createSecret();
-    }
-
-    public function testCreateSecretOverrideSecureDoesNotThrowOnInsecureRNG() {
-        $rng = new TestRNGProvider();
-
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng);
-        $this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret(80, false));
-    }
-
-    public function testCreateSecretDoesNotThrowOnSecureRNGProvider() {
-        $rng = new TestRNGProvider(true);
-
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng);
-        $this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret());
-    }
-
-    public function testCreateSecretGeneratesDesiredAmountOfEntropy() {
-        $rng = new TestRNGProvider(true);
-
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng);
-        $this->assertEquals('A', $tfa->createSecret(5));
-        $this->assertEquals('AB', $tfa->createSecret(6));
-        $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $tfa->createSecret(128));
-        $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', $tfa->createSecret(160));
-        $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', $tfa->createSecret(320));
-        $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567A', $tfa->createSecret(321));
-    }
-
-    public function testEnsureCorrectTimeDoesNotThrowForCorrectTime() {
-        $tpr1 = new TestTimeProvider(123);
-        $tpr2 = new TestTimeProvider(128);
-
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, null, $tpr1);
-        $tfa->ensureCorrectTime(array($tpr2));   // 128 - 123 = 5 => within default leniency
+    public function testEnsureAllTimeProvidersReturnCorrectTime()
+    {
+        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1');
+        $tfa->ensureCorrectTime(array(
+            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'),
+        ));
+        $this->noAssertionsMade();
     }
 
     /**
-     * @expectedException \RobThree\Auth\TwoFactorAuthException
+     * @return void
      */
-    public function testEnsureCorrectTimeThrowsOnIncorrectTime() {
-        $tpr1 = new TestTimeProvider(123);
-        $tpr2 = new TestTimeProvider(124);
-
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', null, null, $tpr1);
-        $tfa->ensureCorrectTime(array($tpr2), 0);    // We force a leniency of 0, 124-123 = 1 so this should throw
-    }
-
-
-    public function testEnsureDefaultTimeProviderReturnsCorrectTime() {
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1');
-        $tfa->ensureCorrectTime(array(new TestTimeProvider(time())), 1);    // Use a leniency of 1, should the time change between both time() calls
-    }
-
-    public function testEnsureAllTimeProvidersReturnCorrectTime() {
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1');
-        $tfa->ensureCorrectTime(array(
-            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'),
-        ));
-    }
-
-    public function testVerifyCodeWorksCorrectly() {
-
+    public function testVerifyCodeWorksCorrectly()
+    {
         $tfa = new TwoFactorAuth('Test', 6, 30);
-        $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847190));
-        $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 29));	//Test discrepancy
-        $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 30));	//Test discrepancy
-        $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 - 1));	//Test discrepancy
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847190));
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 29));	//Test discrepancy
+        $this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 30));	//Test discrepancy
+        $this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 - 1));	//Test discrepancy
 
-        $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 0));	//Test discrepancy
-        $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 35));	//Test discrepancy
-        $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 35));	//Test discrepancy
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 0));	//Test discrepancy
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 35));	//Test discrepancy
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 35));	//Test discrepancy
 
-        $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 65));	//Test discrepancy
-        $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 65));	//Test discrepancy
+        $this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 65));	//Test discrepancy
+        $this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 65));	//Test discrepancy
 
-        $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 + 65));	//Test discrepancy
-        $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 - 65));	//Test discrepancy
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 + 65));	//Test discrepancy
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 - 65));	//Test discrepancy
     }
 
-    public function testVerifyCorrectTimeSliceIsReturned() {
+    /**
+     * @return void
+     */
+    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->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '534113', 3, 1426847190, $timeslice1));
         $this->assertEquals(47561570, $timeslice1);
-        $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '819652', 3, 1426847190, $timeslice2));
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '819652', 3, 1426847190, $timeslice2));
         $this->assertEquals(47561571, $timeslice2);
-        $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '915954', 3, 1426847190, $timeslice3));
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '915954', 3, 1426847190, $timeslice3));
         $this->assertEquals(47561572, $timeslice3);
-        $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 3, 1426847190, $timeslice4));
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 3, 1426847190, $timeslice4));
         $this->assertEquals(47561573, $timeslice4);
-        $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '348401', 3, 1426847190, $timeslice5));
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '348401', 3, 1426847190, $timeslice5));
         $this->assertEquals(47561574, $timeslice5);
-        $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '648525', 3, 1426847190, $timeslice6));
+        $this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '648525', 3, 1426847190, $timeslice6));
         $this->assertEquals(47561575, $timeslice6);
-        $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '170645', 3, 1426847190, $timeslice7));
+        $this->assertTrue($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->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '111111', 3, 1426847190, $timeslice8));
         $this->assertEquals(0, $timeslice8);
     }
 
-    public function testTotpUriIsCorrect() {
-        $qr = new TestQrProvider();
-
-        $tfa = new TwoFactorAuth('Test&Issuer', 6, 30, 'sha1', $qr);
-        $data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
-        $this->assertEquals('test/test', $data['mimetype']);
-        $this->assertEquals('base64', $data['encoding']);
-        $this->assertEquals('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=Test%26Issuer&period=30&algorithm=SHA1&digits=6@200', $data['data']);
-    }
-
     /**
-     * @expectedException \RobThree\Auth\TwoFactorAuthException
+     * @return void
      */
-    public function testGetQRCodeImageAsDataUriThrowsOnInvalidSize() {
-        $qr = new TestQrProvider();
-
-        $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1', $qr);
-        $tfa->getQRCodeImageAsDataUri('Test', 'VMR466AB62ZBOKHE', 0);
-    }
-
-    /**
-     * @expectedException \RobThree\Auth\TwoFactorAuthException
-     */
-    public function testGetCodeThrowsOnInvalidBase32String1() {
+    public function testGetCodeThrowsOnInvalidBase32String1()
+    {
         $tfa = new TwoFactorAuth('Test');
+
+        $this->expectException(TwoFactorAuthException::class);
+
         $tfa->getCode('FOO1BAR8BAZ9');    //1, 8 & 9 are invalid chars
     }
 
     /**
-     * @expectedException \RobThree\Auth\TwoFactorAuthException
+     * @return void
      */
-    public function testGetCodeThrowsOnInvalidBase32String2() {
+    public function testGetCodeThrowsOnInvalidBase32String2()
+    {
         $tfa = new TwoFactorAuth('Test');
+
+        $this->expectException(TwoFactorAuthException::class);
+
         $tfa->getCode('mzxw6===');        //Lowercase
     }
 
-    public function testKnownBase32DecodeTestVectors() {
+    /**
+     * @return void
+     */
+    public function testKnownBase32DecodeTestVectors()
+    {
         // We usually don't test internals (e.g. privates) but since we rely heavily on base32 decoding and don't want
         // to expose this method nor do we want to give people the possibility of implementing / providing their own base32
         // decoding/decoder (as we do with Rng/QR providers for example) we simply test the private base32Decode() method
@@ -226,7 +159,7 @@
         //                                                           Dave Thomas and Andy Hunt -- "Pragmatic Unit Testing
         $tfa = new TwoFactorAuth('Test');
 
-        $method = new ReflectionMethod('RobThree\Auth\TwoFactorAuth', 'base32Decode');
+        $method = new \ReflectionMethod(TwoFactorAuth::class, 'base32Decode');
         $method->setAccessible(true);
 
         // Test vectors from: https://tools.ietf.org/html/rfc4648#page-12
@@ -239,14 +172,18 @@
         $this->assertEquals('foobar', $method->invoke($tfa, 'MZXW6YTBOI======'));
     }
 
-    public function testKnownBase32DecodeUnpaddedTestVectors() {
+    /**
+     * @return void
+     */
+    public function testKnownBase32DecodeUnpaddedTestVectors()
+    {
         // See testKnownBase32DecodeTestVectors() for the rationale behind testing the private base32Decode() method.
         // This test ensures that strings without the padding-char ('=') are also decoded correctly.
         // https://tools.ietf.org/html/rfc4648#page-4:
         //   "In some circumstances, the use of padding ("=") in base-encoded data is not required or used."
         $tfa = new TwoFactorAuth('Test');
 
-        $method = new ReflectionMethod('RobThree\Auth\TwoFactorAuth', 'base32Decode');
+        $method = new \ReflectionMethod(TwoFactorAuth::class, 'base32Decode');
         $method->setAccessible(true);
 
         // Test vectors from: https://tools.ietf.org/html/rfc4648#page-12
@@ -259,8 +196,11 @@
         $this->assertEquals('foobar', $method->invoke($tfa, 'MZXW6YTBOI'));
     }
 
-
-    public function testKnownTestVectors_sha1() {
+    /**
+     * @return void
+     */
+    public function testKnownTestVectors_sha1()
+    {
         //Known test vectors for SHA1: https://tools.ietf.org/html/rfc6238#page-15
         $secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ';   //== base32encode('12345678901234567890')
         $tfa = new TwoFactorAuth('Test', 8, 30, 'sha1');
@@ -272,7 +212,11 @@
         $this->assertEquals('65353130', $tfa->getCode($secret, 20000000000));
     }
 
-    public function testKnownTestVectors_sha256() {
+    /**
+     * @return void
+     */
+    public function testKnownTestVectors_sha256()
+    {
         //Known test vectors for SHA256: https://tools.ietf.org/html/rfc6238#page-15
         $secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZA';   //== base32encode('12345678901234567890123456789012')
         $tfa = new TwoFactorAuth('Test', 8, 30, 'sha256');
@@ -284,7 +228,11 @@
         $this->assertEquals('77737706', $tfa->getCode($secret, 20000000000));
     }
 
-    public function testKnownTestVectors_sha512() {
+    /**
+     * @return void
+     */
+    public function testKnownTestVectors_sha512()
+    {
         //Known test vectors for SHA512: https://tools.ietf.org/html/rfc6238#page-15
         $secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNA';   //== base32encode('1234567890123456789012345678901234567890123456789012345678901234')
         $tfa = new TwoFactorAuth('Test', 8, 30, 'sha512');
@@ -295,115 +243,4 @@
         $this->assertEquals('38618901', $tfa->getCode($secret, 2000000000));
         $this->assertEquals('47863826', $tfa->getCode($secret, 20000000000));
     }
-
-    /**
-     * @requires function random_bytes
-     */
-    public function testCSRNGProvidersReturnExpectedNumberOfBytes() {
-        $rng = new \RobThree\Auth\Providers\Rng\CSRNGProvider();
-        foreach ($this->getRngTestLengths() as $l)
-            $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
-        $this->assertEquals(true, $rng->isCryptographicallySecure());
-    }
-
-    /**
-     * @requires function hash_algos
-     * @requires function hash
-     */
-    public function testHashRNGProvidersReturnExpectedNumberOfBytes() {
-        $rng = new \RobThree\Auth\Providers\Rng\HashRNGProvider();
-        foreach ($this->getRngTestLengths() as $l)
-            $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
-        $this->assertEquals(false, $rng->isCryptographicallySecure());
-    }
-
-    /**
-     * @requires function mcrypt_create_iv
-     */
-    public function testMCryptRNGProvidersReturnExpectedNumberOfBytes() {
-        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());
-        }
-    }
-
-    /**
-     * @requires function openssl_random_pseudo_bytes
-     */
-    public function testStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes() {
-        $rng = new \RobThree\Auth\Providers\Rng\OpenSSLRNGProvider(true);
-        foreach ($this->getRngTestLengths() as $l)
-            $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
-        $this->assertEquals(true, $rng->isCryptographicallySecure());
-    }
-
-    /**
-     * @requires function openssl_random_pseudo_bytes
-     */
-    public function testNonStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes() {
-        $rng = new \RobThree\Auth\Providers\Rng\OpenSSLRNGProvider(false);
-        foreach ($this->getRngTestLengths() as $l)
-            $this->assertEquals($l, strlen($rng->getRandomBytes($l)));
-        $this->assertEquals(false, $rng->isCryptographicallySecure());
-    }
-
-
-    private function getRngTestLengths() {
-        return array(1, 16, 32, 256);
-    }
-
-    private function DecodeDataUri($datauri) {
-        if (preg_match('/data:(?P<mimetype>[\w\.\-\/]+);(?P<encoding>\w+),(?P<data>.*)/', $datauri, $m) === 1) {
-            return array(
-                'mimetype' => $m['mimetype'],
-                'encoding' => $m['encoding'],
-                'data' => base64_decode($m['data'])
-            );
-        }
-        return null;
-    }
 }
-
-class TestRNGProvider implements IRNGProvider {
-    private $isSecure;
-
-    function __construct($isSecure = false) {
-        $this->isSecure = $isSecure;
-    }
-
-    public function getRandomBytes($bytecount) {
-        $result = '';
-        for ($i=0; $i<$bytecount; $i++)
-            $result.=chr($i);
-        return $result;
-
-    }
-
-    public function isCryptographicallySecure() {
-        return $this->isSecure;
-    }
-}
-
-class TestQrProvider implements IQRCodeProvider {
-    public function getQRCodeImage($qrtext, $size) {
-        return $qrtext . '@' . $size;
-    }
-
-    public function getMimeType() {
-        return 'test/test';
-    }
-}
-
-class TestTimeProvider implements ITimeProvider {
-    private $time;
-
-    function __construct($time) {
-        $this->time = $time;
-    }
-
-    public function getTime() {
-        return $this->time;
-    }
-}
\ No newline at end of file