Parcourir la source

Added 2FA - Google for now! Fixed GH#19 - FeatHub-13

causefx il y a 7 ans
Parent
commit
29a2575766
82 fichiers modifiés avec 7438 ajouts et 29 suppressions
  1. 2 1
      api/composer.json
  2. 232 1
      api/composer.lock
  3. 78 0
      api/functions/2fa-functions.php
  4. 13 0
      api/functions/api-functions.php
  5. 4 2
      api/functions/token-functions.php
  6. 76 0
      api/index.php
  7. 18 2
      api/pages/login.php
  8. 3 3
      api/plugins/js/chat.js
  9. 16 18
      api/plugins/misc/emailTemplates/default.php
  10. 1 0
      api/vendor/composer/autoload_files.php
  11. 5 0
      api/vendor/composer/autoload_psr4.php
  12. 29 0
      api/vendor/composer/autoload_static.php
  13. 239 0
      api/vendor/composer/installed.json
  14. 2 0
      api/vendor/paragonie/constant_time_encoding/.gitignore
  15. 18 0
      api/vendor/paragonie/constant_time_encoding/.travis.yml
  16. 48 0
      api/vendor/paragonie/constant_time_encoding/LICENSE.txt
  17. 79 0
      api/vendor/paragonie/constant_time_encoding/README.md
  18. 40 0
      api/vendor/paragonie/constant_time_encoding/composer.json
  19. 29 0
      api/vendor/paragonie/constant_time_encoding/phpunit.xml.dist
  20. 10 0
      api/vendor/paragonie/constant_time_encoding/psalm.xml
  21. 468 0
      api/vendor/paragonie/constant_time_encoding/src/Base32.php
  22. 111 0
      api/vendor/paragonie/constant_time_encoding/src/Base32Hex.php
  23. 268 0
      api/vendor/paragonie/constant_time_encoding/src/Base64.php
  24. 88 0
      api/vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php
  25. 82 0
      api/vendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php
  26. 95 0
      api/vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php
  27. 85 0
      api/vendor/paragonie/constant_time_encoding/src/Binary.php
  28. 52 0
      api/vendor/paragonie/constant_time_encoding/src/EncoderInterface.php
  29. 260 0
      api/vendor/paragonie/constant_time_encoding/src/Encoding.php
  30. 159 0
      api/vendor/paragonie/constant_time_encoding/src/Hex.php
  31. 175 0
      api/vendor/paragonie/constant_time_encoding/src/RFC4648.php
  32. 49 0
      api/vendor/paragonie/constant_time_encoding/tests/Base32HexTest.php
  33. 50 0
      api/vendor/paragonie/constant_time_encoding/tests/Base32Test.php
  34. 34 0
      api/vendor/paragonie/constant_time_encoding/tests/Base64DotSlashOrderedTest.php
  35. 34 0
      api/vendor/paragonie/constant_time_encoding/tests/Base64DotSlashTest.php
  36. 79 0
      api/vendor/paragonie/constant_time_encoding/tests/Base64Test.php
  37. 58 0
      api/vendor/paragonie/constant_time_encoding/tests/Base64UrlSafeTest.php
  38. 307 0
      api/vendor/paragonie/constant_time_encoding/tests/EncodingTest.php
  39. 39 0
      api/vendor/paragonie/constant_time_encoding/tests/HexTest.php
  40. 84 0
      api/vendor/paragonie/constant_time_encoding/tests/RFC4648Test.php
  41. 3 0
      api/vendor/pragmarx/google2fa/.gitignore
  42. 40 0
      api/vendor/pragmarx/google2fa/.scrutinizer.yml
  43. 33 0
      api/vendor/pragmarx/google2fa/.travis.yml
  44. 7 0
      api/vendor/pragmarx/google2fa/LICENSE.md
  45. 276 0
      api/vendor/pragmarx/google2fa/README.md
  46. 29 0
      api/vendor/pragmarx/google2fa/RELICENSED.md
  47. 69 0
      api/vendor/pragmarx/google2fa/changelog.md
  48. 40 0
      api/vendor/pragmarx/google2fa/composer.json
  49. 1742 0
      api/vendor/pragmarx/google2fa/composer.lock
  50. BIN
      api/vendor/pragmarx/google2fa/docs/playground.jpg
  51. 34 0
      api/vendor/pragmarx/google2fa/phpunit.xml
  52. 10 0
      api/vendor/pragmarx/google2fa/src/Exceptions/IncompatibleWithGoogleAuthenticatorException.php
  53. 10 0
      api/vendor/pragmarx/google2fa/src/Exceptions/InsecureCallException.php
  54. 10 0
      api/vendor/pragmarx/google2fa/src/Exceptions/InvalidCharactersException.php
  55. 10 0
      api/vendor/pragmarx/google2fa/src/Exceptions/SecretKeyTooShortException.php
  56. 354 0
      api/vendor/pragmarx/google2fa/src/Google2FA.php
  57. 135 0
      api/vendor/pragmarx/google2fa/src/Support/Base32.php
  58. 21 0
      api/vendor/pragmarx/google2fa/src/Support/Constants.php
  59. 91 0
      api/vendor/pragmarx/google2fa/src/Support/QRCode.php
  60. 16 0
      api/vendor/pragmarx/google2fa/src/Support/Url.php
  61. 0 0
      api/vendor/pragmarx/google2fa/tests/.gitkeep
  62. 16 0
      api/vendor/pragmarx/google2fa/tests/Constants.php
  63. 224 0
      api/vendor/pragmarx/google2fa/tests/Google2FATest.php
  64. 42 0
      api/vendor/pragmarx/google2fa/tests/bootstrap.php
  65. 2 0
      api/vendor/pragmarx/google2fa/upgrading.md
  66. 19 0
      api/vendor/symfony/polyfill-php56/LICENSE
  67. 138 0
      api/vendor/symfony/polyfill-php56/Php56.php
  68. 15 0
      api/vendor/symfony/polyfill-php56/README.md
  69. 38 0
      api/vendor/symfony/polyfill-php56/bootstrap.php
  70. 32 0
      api/vendor/symfony/polyfill-php56/composer.json
  71. 18 0
      api/vendor/symfony/polyfill-util/Binary.php
  72. 65 0
      api/vendor/symfony/polyfill-util/BinaryNoFuncOverload.php
  73. 67 0
      api/vendor/symfony/polyfill-util/BinaryOnFuncOverload.php
  74. 19 0
      api/vendor/symfony/polyfill-util/LICENSE
  75. 84 0
      api/vendor/symfony/polyfill-util/LegacyTestListener.php
  76. 13 0
      api/vendor/symfony/polyfill-util/README.md
  77. 30 0
      api/vendor/symfony/polyfill-util/composer.json
  78. 10 0
      css/organizr.css
  79. 0 0
      css/organizr.min.css
  80. 6 2
      js/custom.js
  81. 0 0
      js/custom.min.js
  82. 151 0
      js/functions.js

+ 2 - 1
api/composer.json

@@ -8,6 +8,7 @@
         "kryptonit3/sonarr": "1.0.6.1",
         "kryptonit3/couchpotato": "^1.0",
         "kryptonit3/sickrage": "^1.0",
-        "pusher/pusher-php-server": "^3.2"
+        "pusher/pusher-php-server": "^3.2",
+        "pragmarx/google2fa": "^3.0"
     }
 }

+ 232 - 1
api/composer.lock

@@ -4,7 +4,7 @@
         "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": "11882b856a95c0d425e40bd5393ee3a0",
+    "content-hash": "0e5ee280433e4a8e418c7b3a14dc39ff",
     "packages": [
         {
             "name": "composer/semver",
@@ -482,6 +482,68 @@
             ],
             "time": "2017-09-01T08:23:26+00:00"
         },
+        {
+            "name": "paragonie/constant_time_encoding",
+            "version": "v2.2.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/constant_time_encoding.git",
+                "reference": "eccf915f45f911bfb189d1d1638d940ec6ee6e33"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/eccf915f45f911bfb189d1d1638d940ec6ee6e33",
+                "reference": "eccf915f45f911bfb189d1d1638d940ec6ee6e33",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6|^7",
+                "vimeo/psalm": "^1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "ParagonIE\\ConstantTime\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com",
+                    "role": "Maintainer"
+                },
+                {
+                    "name": "Steve 'Sc00bz' Thomas",
+                    "email": "steve@tobtu.com",
+                    "homepage": "https://www.tobtu.com",
+                    "role": "Original Developer"
+                }
+            ],
+            "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
+            "keywords": [
+                "base16",
+                "base32",
+                "base32_decode",
+                "base32_encode",
+                "base64",
+                "base64_decode",
+                "base64_encode",
+                "bin2hex",
+                "encoding",
+                "hex",
+                "hex2bin",
+                "rfc4648"
+            ],
+            "time": "2018-03-10T19:47:49+00:00"
+        },
         {
             "name": "paragonie/random_compat",
             "version": "v9.99.99",
@@ -675,6 +737,67 @@
             "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
             "time": "2018-01-05T13:19:58+00:00"
         },
+        {
+            "name": "pragmarx/google2fa",
+            "version": "v3.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/antonioribeiro/google2fa.git",
+                "reference": "6949226739e4424f40031e6f1c96b1fd64047335"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/6949226739e4424f40031e6f1c96b1fd64047335",
+                "reference": "6949226739e4424f40031e6f1c96b1fd64047335",
+                "shasum": ""
+            },
+            "require": {
+                "paragonie/constant_time_encoding": "~1.0|~2.0",
+                "paragonie/random_compat": ">=1",
+                "php": ">=5.4",
+                "symfony/polyfill-php56": "~1.2"
+            },
+            "require-dev": {
+                "bacon/bacon-qr-code": "~1.0",
+                "phpunit/phpunit": "~4|~5|~6"
+            },
+            "suggest": {
+                "bacon/bacon-qr-code": "Required to generate inline QR Codes."
+            },
+            "type": "library",
+            "extra": {
+                "component": "package",
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PragmaRX\\Google2FA\\": "src/",
+                    "PragmaRX\\Google2FA\\Tests\\": "tests/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Antonio Carlos Ribeiro",
+                    "email": "acr@antoniocarlosribeiro.com",
+                    "role": "Creator & Designer"
+                }
+            ],
+            "description": "A One Time Password Authentication package, compatible with Google Authenticator.",
+            "keywords": [
+                "2fa",
+                "Authentication",
+                "Two Factor Authentication",
+                "google2fa",
+                "laravel"
+            ],
+            "time": "2018-08-29T13:28:06+00:00"
+        },
         {
             "name": "psr/http-message",
             "version": "1.0.1",
@@ -874,6 +997,114 @@
                 "sockets"
             ],
             "time": "2016-10-13T00:11:37+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php56",
+            "version": "v1.9.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php56.git",
+                "reference": "7b4fc009172cc0196535b0328bd1226284a28000"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/7b4fc009172cc0196535b0328bd1226284a28000",
+                "reference": "7b4fc009172cc0196535b0328bd1226284a28000",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "symfony/polyfill-util": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php56\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-08-06T14:22:27+00:00"
+        },
+        {
+            "name": "symfony/polyfill-util",
+            "version": "v1.9.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-util.git",
+                "reference": "8e15d04ba3440984d23e7964b2ee1d25c8de1581"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8e15d04ba3440984d23e7964b2ee1d25c8de1581",
+                "reference": "8e15d04ba3440984d23e7964b2ee1d25c8de1581",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Util\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony utilities for portability of PHP codes",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compat",
+                "compatibility",
+                "polyfill",
+                "shim"
+            ],
+            "time": "2018-08-06T14:22:27+00:00"
         }
     ],
     "packages-dev": [],

+ 78 - 0
api/functions/2fa-functions.php

@@ -0,0 +1,78 @@
+<?php
+function create2FA($type)
+{
+	$result['type'] = $type;
+	switch ($type) {
+		case 'google':
+			try {
+				$google2fa = new PragmaRX\Google2FA\Google2FA();
+				$google2fa->setAllowInsecureCallToGoogleApis(true);
+				$result['secret'] = $google2fa->generateSecretKey();
+				$result['url'] = $google2fa->getQRCodeGoogleUrl(
+					$GLOBALS['title'],
+					$GLOBALS['organizrUser']['username'],
+					$result['secret']
+				);
+			} catch (PragmaRX\Google2FA\Exceptions\InsecureCallException $e) {
+				return false;
+			}
+			break;
+		default:
+			return false;
+	}
+	return $result;
+}
+
+function save2FA($secret, $type)
+{
+	try {
+		$connect = new Dibi\Connection([
+			'driver' => 'sqlite3',
+			'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
+		]);
+		$connect->query('
+            UPDATE users SET', [
+			'auth_service' => $type . '::' . $secret
+		], '
+            WHERE id=?', $GLOBALS['organizrUser']['userID']);
+		writeLog('success', 'User Management Function - User added 2FA', $GLOBALS['organizrUser']['username']);
+		return true;
+	} catch (Dibi\Exception $e) {
+		writeLog('error', 'User Management Function - Error Adding User 2FA', $GLOBALS['organizrUser']['username']);
+		return false;
+	}
+}
+
+function verify2FA($secret, $code, $type)
+{
+	switch ($type) {
+		case 'google':
+			$google2fa = new PragmaRX\Google2FA\Google2FA();
+			$google2fa->setWindow(0);
+			$valid = $google2fa->verifyKey($secret, $code);
+			break;
+		default:
+			return false;
+	}
+	return ($valid) ? true : false;
+}
+
+function remove2FA()
+{
+	try {
+		$connect = new Dibi\Connection([
+			'driver' => 'sqlite3',
+			'database' => $GLOBALS['dbLocation'] . $GLOBALS['dbName'],
+		]);
+		$connect->query('
+            UPDATE users SET', [
+			'auth_service' => 'internal'
+		], '
+            WHERE id=?', $GLOBALS['organizrUser']['userID']);
+		writeLog('success', 'User Management Function - User removed 2FA', $GLOBALS['organizrUser']['username']);
+		return true;
+	} catch (Dibi\Exception $e) {
+		writeLog('error', 'User Management Function - Error Removing User 2FA', $GLOBALS['organizrUser']['username']);
+		return false;
+	}
+}

+ 13 - 0
api/functions/api-functions.php

@@ -70,6 +70,19 @@ function login($array)
                     	WHERE id=?', $result['id']);
 					writeLog('success', 'Login Function - User Password updated from backend', $username);
 				}
+				// 2FA might go here
+				if ($result['auth_service'] !== 'internal' && strpos($result['auth_service'], '::') !== false) {
+					$TFA = explode('::', $result['auth_service']);
+					// Is code with login info?
+					if ($tfaCode == '') {
+						return '2FA';
+					} else {
+						if (!verify2FA($TFA[1], $tfaCode, $TFA[0])) {
+							return '2FA-incorrect';
+						}
+					}
+				}
+				// End 2FA
 				// authentication passed - 1) mark active and update token
 				if (createToken($result['username'], $result['email'], $result['image'], $result['group'], $result['group_id'], $GLOBALS['organizrHash'], $days)) {
 					writeLoginLog($username, 'success');

+ 4 - 2
api/functions/token-functions.php

@@ -128,7 +128,8 @@ function validateToken($token, $global = false)
 					"image" => $result['image'],
 					"userID" => $result['id'],
 					"loggedin" => true,
-					"locked" => $result['locked']
+					"locked" => $result['locked'],
+					"authService" => explode('::', $result['auth_service'])[0]
 				);
 			} catch (Dibi\Exception $e) {
 				$GLOBALS['organizrUser'] = false;
@@ -160,7 +161,8 @@ function getOrganizrUserToken()
 			"image" => getGuest()['image'],
 			"userID" => null,
 			"loggedin" => false,
-			"locked" => false
+			"locked" => false,
+			"authService" => null
 		);
 	}
 }

+ 76 - 0
api/index.php

@@ -996,6 +996,82 @@ switch ($function) {
 				break;
 		}
 		break;
+	case 'v1_2fa_create':
+		switch ($method) {
+			case 'POST':
+				if (qualifyRequest(998)) {
+					$result['status'] = 'success';
+					$result['statusText'] = 'success';
+					$result['data'] = create2FA($_POST['data']['type']);
+				} else {
+					$result['status'] = 'error';
+					$result['statusText'] = 'API/Token invalid or not set';
+					$result['data'] = null;
+				}
+				break;
+			default:
+				$result['status'] = 'error';
+				$result['statusText'] = 'The function requested is not defined for method: ' . $method;
+				break;
+		}
+		break;
+	case 'v1_2fa_save':
+		switch ($method) {
+			case 'POST':
+				if (qualifyRequest(998)) {
+					$result['status'] = 'success';
+					$result['statusText'] = 'success';
+					$result['data'] = save2FA($_POST['data']['secret'], $_POST['data']['type']);
+				} else {
+					$result['status'] = 'error';
+					$result['statusText'] = 'API/Token invalid or not set';
+					$result['data'] = null;
+				}
+				break;
+			default:
+				$result['status'] = 'error';
+				$result['statusText'] = 'The function requested is not defined for method: ' . $method;
+				break;
+		}
+		break;
+	case 'v1_2fa_verify':
+		switch ($method) {
+			case 'POST':
+				if (qualifyRequest(998)) {
+					$result['status'] = 'success';
+					$result['statusText'] = 'success';
+					$result['data'] = verify2FA($_POST['data']['secret'], $_POST['data']['code'], $_POST['data']['type']);
+				} else {
+					$result['status'] = 'error';
+					$result['statusText'] = 'API/Token invalid or not set';
+					$result['data'] = null;
+				}
+				break;
+			default:
+				$result['status'] = 'error';
+				$result['statusText'] = 'The function requested is not defined for method: ' . $method;
+				break;
+		}
+		break;
+	case 'v1_2fa_remove':
+		switch ($method) {
+			case 'GET':
+				if (qualifyRequest(998)) {
+					$result['status'] = 'success';
+					$result['statusText'] = 'success';
+					$result['data'] = remove2FA();
+				} else {
+					$result['status'] = 'error';
+					$result['statusText'] = 'API/Token invalid or not set';
+					$result['data'] = null;
+				}
+				break;
+			default:
+				$result['status'] = 'error';
+				$result['statusText'] = 'The function requested is not defined for method: ' . $method;
+				break;
+		}
+		break;
 	case 'v1_logout':
 		switch ($method) {
 			case 'GET':

+ 18 - 2
api/pages/login.php

@@ -5,9 +5,25 @@ $pageLogin = '
 <section id="wrapper" class="login-register">
   <div class="login-box login-sidebar animated slideInRight">
     <div class="white-box">
-      <form class="form-horizontal form-material" id="loginform" onsubmit="return false;">
+      <form class="form-horizontal" id="loginform" onsubmit="return false;">
         <a href="javascript:void(0)" class="text-center db visible-xs" id="login-logo">' . logoOrText() . '</a>
-
+		<div id="tfa-div" class="form-group hidden">
+          <div class="col-xs-12">
+            <div class="panel panel-warning animated tada">
+                <div class="panel-heading"> 2FA
+                    <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a> <a href="#" data-perform="panel-dismiss"><i class="ti-close"></i></a> </div>
+                </div>
+                <div class="panel-wrapper collapse in" aria-expanded="true">
+                    <div class="panel-body">
+	                    <div class="input-group" style="width: 100%;">
+	                        <div class="input-group-addon hidden-xs"><i class="ti-lock"></i></div>
+	                        <input type="text" class="form-control tfa-input" name="tfaCode" placeholder="Code" autocomplete="off" autocorrect="off" autocapitalize="off" maxlength="6" spellcheck="false" autofocus="">
+	                    </div>
+                    </div>
+                </div>
+            </div>
+          </div>
+        </div>
         <div class="form-group m-t-40">
           <div class="col-xs-12">
             <input class="form-control" name="username" type="text" required="" placeholder="Username" autofocus>

+ 3 - 3
api/plugins/js/chat.js

@@ -26,7 +26,7 @@ function chatLaunch(){
                                     <div class="col-sm-12">
                                         <textarea class="form-control chat-input-send" placeholder="Type your message"></textarea>
                                         <div class="custom-send">
-                                            <button class="btn btn-info btn-rounded custom-send-button" type="button">Send</button>
+                                            <button type="button" class="btn btn-info btn-lg custom-send-button"><i class="fa fa-paper-plane fa-2x"></i> </button>
                                         </div>
                                     </div>
                                 </div>
@@ -53,7 +53,7 @@ function chatLaunch(){
                     function(data) {
                         formatMessage(data);
                         $('.chat-list').append(formatMessage(data));
-                        $('.custom-send').html('<button class="btn btn-info btn-rounded custom-send-button" type="button">Send</button>');
+                        $('.custom-send').html('<button type="button" class="btn btn-info btn-lg custom-send-button"><i class="fa fa-paper-plane fa-2x"></i> </button>');
                         $(".chat-list").scrollTop($(".chat-list")[0].scrollHeight);
                         if($('#container-plugin-chat').hasClass('hidden')){
                             var chatSound =  new Audio(activeInfo.plugins.includes["CHAT-newMessageSound-include"]);
@@ -135,7 +135,7 @@ $('body').on('click', '.custom-send-button', function(e) {
         // Clear the message input field
         $('.chat-input-send').val('');
         // Show a loading image while sending
-        $('.custom-send').html('<button class="btn btn-info btn-rounded custom-send-button" disabled type="button"><i class="fa fa-spinner fa-pulse "></i></button>');
+        $('.custom-send').html('<button type="button" class="btn btn-info btn-lg custom-send-button" disabled><i class="fa fa-spinner fa-pulse fa-2x"></i> </button>');
     }
 });
 function formatMessage(msg){

+ 16 - 18
api/plugins/misc/emailTemplates/default.php

@@ -1,7 +1,7 @@
 <?php
 switch ($extra) {
-    case 'invite':
-        $button = '
+	case 'invite':
+		$button = '
         <table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnButtonBlock" style="min-width:100%;">
             <tbody class="mcnButtonBlockOuter">
                 <tr>
@@ -10,7 +10,7 @@ switch ($extra) {
                             <tbody>
                                 <tr>
                                     <td align="center" valign="middle" class="mcnButtonContent" style="font-family: Helvetica; font-size: 18px; padding: 18px;">
-                                        <a class="mcnButton " title="Button Text" href="'.getServerPath(true).'?invite='.$email['inviteCode'].'" target="_self" style="font-weight: bold;letter-spacing: -0.5px;line-height: 100%;text-align: center;text-decoration: none;color: #FFFFFF;">Use Invite Code</a>
+                                        <a class="mcnButton " title="Button Text" href="' . getServerPath(true) . '?invite=' . $email['inviteCode'] . '" target="_self" style="font-weight: bold;letter-spacing: -0.5px;line-height: 100%;text-align: center;text-decoration: none;color: #FFFFFF;">Use Invite Code</a>
                                     </td>
                                 </tr>
                             </tbody>
@@ -20,9 +20,9 @@ switch ($extra) {
             </tbody>
         </table>
         ';
-        break;
-    case 'reset':
-        $button = '
+		break;
+	case 'reset':
+		$button = '
         <table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnButtonBlock" style="min-width:100%;">
             <tbody class="mcnButtonBlockOuter">
                 <tr>
@@ -31,7 +31,7 @@ switch ($extra) {
                             <tbody>
                                 <tr>
                                     <td align="center" valign="middle" class="mcnButtonContent" style="font-family: Helvetica; font-size: 18px; padding: 18px;">
-                                        <a class="mcnButton " title="Reset Password" href="'.getServerPath(true).'" target="_self" style="font-weight: bold;letter-spacing: -0.5px;line-height: 100%;text-align: center;text-decoration: none;color: #FFFFFF;">Goto My Site</a>
+                                        <a class="mcnButton " title="Reset Password" href="' . getServerPath(true) . '" target="_self" style="font-weight: bold;letter-spacing: -0.5px;line-height: 100%;text-align: center;text-decoration: none;color: #FFFFFF;">Goto My Site</a>
                                     </td>
                                 </tr>
                             </tbody>
@@ -41,12 +41,11 @@ switch ($extra) {
             </tbody>
         </table>
         ';
-        break;
-    default:
-        $button = null;
-        break;
+		break;
+	default:
+		$button = null;
+		break;
 }
-
 $info = '
 <table border="0" cellpadding="0" cellspacing="0" width="100%" class="mcnBoxedTextBlock" style="min-width:100%;">
     <!--[if gte mso 9]>
@@ -69,7 +68,7 @@ $info = '
                                     <tbody>
                                         <tr>
                                             <td valign="top" class="mcnTextContent" style="padding: 18px;">
-                                                <h3 style="text-align:center;">'.getServerPath(true).'</h3>
+                                                <h3 style="text-align:center;">' . getServerPath(true) . '</h3>
                                             </td>
                                         </tr>
                                     </tbody>
@@ -91,8 +90,7 @@ $info = '
     </tbody>
 </table>
 ';
-
- $email = '
+$email = '
 <!doctype html>
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
 
@@ -852,7 +850,7 @@ $info = '
                                                                     <tr>
                                                                         <td class="mcnImageContent" valign="top" style="padding-right: 9px; padding-left: 9px; padding-top: 0; padding-bottom: 0; text-align:center;">
 
-                                                                            <img align="center" alt="" src="'.$GLOBALS['PHPMAILER-logo'].'" width="564" style="max-width:700px; padding-bottom: 0; display: inline !important; vertical-align: bottom;" class="mcnImage">
+                                                                            <img align="center" alt="" src="' . $GLOBALS['PHPMAILER-logo'] . '" width="564" style="max-width:700px; padding-bottom: 0; display: inline !important; vertical-align: bottom;" class="mcnImage">
 
                                                                         </td>
                                                                     </tr>
@@ -900,7 +898,7 @@ $info = '
 
                                                                         <td valign="top" class="mcnTextContent" style="padding-top:0; padding-right:18px; padding-bottom:9px; padding-left:18px;">
 
-                                                                            '.$body.'
+                                                                            ' . $body . '
 
                                                                         </td>
                                                                     </tr>
@@ -919,7 +917,7 @@ $info = '
                                                 </tbody>
                                             </table>
 
-                                            '.$button.$info.'
+                                            ' . $button . $info . '
                                         </td>
                                     </tr>
                                 </table>

+ 1 - 0
api/vendor/composer/autoload_files.php

@@ -10,5 +10,6 @@ return array(
     'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
     '3109cb1a231dcd04bee1f9f620d46975' => $vendorDir . '/paragonie/sodium_compat/autoload.php',
+    'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
     '0097ca414fcb37c7130ac24b05f485f8' => $vendorDir . '/dibi/dibi/src/loader.php',
 );

+ 5 - 0
api/vendor/composer/autoload_psr4.php

@@ -6,9 +6,14 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
+    'Symfony\\Polyfill\\Util\\' => array($vendorDir . '/symfony/polyfill-util'),
+    'Symfony\\Polyfill\\Php56\\' => array($vendorDir . '/symfony/polyfill-php56'),
     'Pusher\\' => array($vendorDir . '/pusher/pusher-php-server/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
     'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
+    'PragmaRX\\Google2FA\\Tests\\' => array($vendorDir . '/pragmarx/google2fa/tests'),
+    'PragmaRX\\Google2FA\\' => array($vendorDir . '/pragmarx/google2fa/src'),
+    'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
     'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
     'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'),
     'Kryptonit3\\Sonarr\\' => array($vendorDir . '/kryptonit3/sonarr/src'),

+ 29 - 0
api/vendor/composer/autoload_static.php

@@ -11,15 +11,24 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
         '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
         '3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php',
+        'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
         '0097ca414fcb37c7130ac24b05f485f8' => __DIR__ . '/..' . '/dibi/dibi/src/loader.php',
     );
 
     public static $prefixLengthsPsr4 = array (
+        'S' => 
+        array (
+            'Symfony\\Polyfill\\Util\\' => 22,
+            'Symfony\\Polyfill\\Php56\\' => 23,
+        ),
         'P' => 
         array (
             'Pusher\\' => 7,
             'Psr\\Log\\' => 8,
             'Psr\\Http\\Message\\' => 17,
+            'PragmaRX\\Google2FA\\Tests\\' => 25,
+            'PragmaRX\\Google2FA\\' => 19,
+            'ParagonIE\\ConstantTime\\' => 23,
             'PHPMailer\\PHPMailer\\' => 20,
         ),
         'L' => 
@@ -45,6 +54,14 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
     );
 
     public static $prefixDirsPsr4 = array (
+        'Symfony\\Polyfill\\Util\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-util',
+        ),
+        'Symfony\\Polyfill\\Php56\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-php56',
+        ),
         'Pusher\\' => 
         array (
             0 => __DIR__ . '/..' . '/pusher/pusher-php-server/src',
@@ -57,6 +74,18 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/psr/http-message/src',
         ),
+        'PragmaRX\\Google2FA\\Tests\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/pragmarx/google2fa/tests',
+        ),
+        'PragmaRX\\Google2FA\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/pragmarx/google2fa/src',
+        ),
+        'ParagonIE\\ConstantTime\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src',
+        ),
         'PHPMailer\\PHPMailer\\' => 
         array (
             0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',

+ 239 - 0
api/vendor/composer/installed.json

@@ -899,5 +899,244 @@
             "rest",
             "trigger"
         ]
+    },
+    {
+        "name": "symfony/polyfill-util",
+        "version": "v1.9.0",
+        "version_normalized": "1.9.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/polyfill-util.git",
+            "reference": "8e15d04ba3440984d23e7964b2ee1d25c8de1581"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8e15d04ba3440984d23e7964b2ee1d25c8de1581",
+            "reference": "8e15d04ba3440984d23e7964b2ee1d25c8de1581",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.3"
+        },
+        "time": "2018-08-06T14:22:27+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.9-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Polyfill\\Util\\": ""
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Nicolas Grekas",
+                "email": "p@tchwork.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Symfony utilities for portability of PHP codes",
+        "homepage": "https://symfony.com",
+        "keywords": [
+            "compat",
+            "compatibility",
+            "polyfill",
+            "shim"
+        ]
+    },
+    {
+        "name": "symfony/polyfill-php56",
+        "version": "v1.9.0",
+        "version_normalized": "1.9.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/polyfill-php56.git",
+            "reference": "7b4fc009172cc0196535b0328bd1226284a28000"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/7b4fc009172cc0196535b0328bd1226284a28000",
+            "reference": "7b4fc009172cc0196535b0328bd1226284a28000",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.3",
+            "symfony/polyfill-util": "~1.0"
+        },
+        "time": "2018-08-06T14:22:27+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.9-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Polyfill\\Php56\\": ""
+            },
+            "files": [
+                "bootstrap.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Nicolas Grekas",
+                "email": "p@tchwork.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
+        "homepage": "https://symfony.com",
+        "keywords": [
+            "compatibility",
+            "polyfill",
+            "portable",
+            "shim"
+        ]
+    },
+    {
+        "name": "paragonie/constant_time_encoding",
+        "version": "v2.2.2",
+        "version_normalized": "2.2.2.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/paragonie/constant_time_encoding.git",
+            "reference": "eccf915f45f911bfb189d1d1638d940ec6ee6e33"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/eccf915f45f911bfb189d1d1638d940ec6ee6e33",
+            "reference": "eccf915f45f911bfb189d1d1638d940ec6ee6e33",
+            "shasum": ""
+        },
+        "require": {
+            "php": "^7"
+        },
+        "require-dev": {
+            "phpunit/phpunit": "^6|^7",
+            "vimeo/psalm": "^1"
+        },
+        "time": "2018-03-10T19:47:49+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "ParagonIE\\ConstantTime\\": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Paragon Initiative Enterprises",
+                "email": "security@paragonie.com",
+                "homepage": "https://paragonie.com",
+                "role": "Maintainer"
+            },
+            {
+                "name": "Steve 'Sc00bz' Thomas",
+                "email": "steve@tobtu.com",
+                "homepage": "https://www.tobtu.com",
+                "role": "Original Developer"
+            }
+        ],
+        "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
+        "keywords": [
+            "base16",
+            "base32",
+            "base32_decode",
+            "base32_encode",
+            "base64",
+            "base64_decode",
+            "base64_encode",
+            "bin2hex",
+            "encoding",
+            "hex",
+            "hex2bin",
+            "rfc4648"
+        ]
+    },
+    {
+        "name": "pragmarx/google2fa",
+        "version": "v3.0.3",
+        "version_normalized": "3.0.3.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/antonioribeiro/google2fa.git",
+            "reference": "6949226739e4424f40031e6f1c96b1fd64047335"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/6949226739e4424f40031e6f1c96b1fd64047335",
+            "reference": "6949226739e4424f40031e6f1c96b1fd64047335",
+            "shasum": ""
+        },
+        "require": {
+            "paragonie/constant_time_encoding": "~1.0|~2.0",
+            "paragonie/random_compat": ">=1",
+            "php": ">=5.4",
+            "symfony/polyfill-php56": "~1.2"
+        },
+        "require-dev": {
+            "bacon/bacon-qr-code": "~1.0",
+            "phpunit/phpunit": "~4|~5|~6"
+        },
+        "suggest": {
+            "bacon/bacon-qr-code": "Required to generate inline QR Codes."
+        },
+        "time": "2018-08-29T13:28:06+00:00",
+        "type": "library",
+        "extra": {
+            "component": "package",
+            "branch-alias": {
+                "dev-master": "2.0-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "PragmaRX\\Google2FA\\": "src/",
+                "PragmaRX\\Google2FA\\Tests\\": "tests/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Antonio Carlos Ribeiro",
+                "email": "acr@antoniocarlosribeiro.com",
+                "role": "Creator & Designer"
+            }
+        ],
+        "description": "A One Time Password Authentication package, compatible with Google Authenticator.",
+        "keywords": [
+            "2fa",
+            "Authentication",
+            "Two Factor Authentication",
+            "google2fa",
+            "laravel"
+        ]
     }
 ]

+ 2 - 0
api/vendor/paragonie/constant_time_encoding/.gitignore

@@ -0,0 +1,2 @@
+.idea/
+vendor/

+ 18 - 0
api/vendor/paragonie/constant_time_encoding/.travis.yml

@@ -0,0 +1,18 @@
+language: php
+sudo: false
+
+php:
+    - "7.0"
+    - "7.1"
+    - "7.2"
+
+matrix:
+    fast_finish: true
+
+install:
+    - composer self-update
+    - composer update
+
+script:
+    - vendor/bin/phpunit
+    - vendor/bin/psalm

+ 48 - 0
api/vendor/paragonie/constant_time_encoding/LICENSE.txt

@@ -0,0 +1,48 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 - 2018 Paragon Initiative Enterprises
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+------------------------------------------------------------------------------
+This library was based on the work of Steve "Sc00bz" Thomas.
+------------------------------------------------------------------------------
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Steve Thomas
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+

+ 79 - 0
api/vendor/paragonie/constant_time_encoding/README.md

@@ -0,0 +1,79 @@
+# Constant-Time Encoding
+
+[![Build Status](https://travis-ci.org/paragonie/constant_time_encoding.svg?branch=master)](https://travis-ci.org/paragonie/constant_time_encoding)
+[![Latest Stable Version](https://poser.pugx.org/paragonie/constant_time_encoding/v/stable)](https://packagist.org/packages/paragonie/constant_time_encoding)
+[![Latest Unstable Version](https://poser.pugx.org/paragonie/constant_time_encoding/v/unstable)](https://packagist.org/packages/paragonie/constant_time_encoding)
+[![License](https://poser.pugx.org/paragonie/constant_time_encoding/license)](https://packagist.org/packages/paragonie/constant_time_encoding)
+[![Downloads](https://img.shields.io/packagist/dt/paragonie/constant_time_encoding.svg)](https://packagist.org/packages/paragonie/constant_time_encoding)
+
+Based on the [constant-time base64 implementation made by Steve "Sc00bz" Thomas](https://github.com/Sc00bz/ConstTimeEncoding),
+this library aims to offer character encoding functions that do not leak
+information about what you are encoding/decoding via processor cache 
+misses. Further reading on [cache-timing attacks](http://blog.ircmaxell.com/2014/11/its-all-about-time.html).
+
+Our fork offers the following enchancements:
+
+* `mbstring.func_overload` resistance
+* Unit tests
+* Composer- and Packagist-ready
+* Base16 encoding
+* Base32 encoding
+* Uses `pack()` and `unpack()` instead of `chr()` and `ord()`
+
+## PHP Version Requirements
+
+Version 2 of this library should work on **PHP 7** or newer. For PHP 5
+support, see [the v1.x branch](https://github.com/paragonie/constant_time_encoding/tree/v1.x).
+
+If you are adding this as a dependency to a project intended to work on both PHP 5 and PHP 7, please set the required version to `^1|^2` instead of just `^1` or `^2`.
+
+## How to Install
+
+```sh
+composer require paragonie/constant_time_encoding
+```
+
+## How to Use
+
+```php
+use \ParagonIE\ConstantTime\Encoding;
+
+// possibly (if applicable): 
+// require 'vendor/autoload.php';
+
+$data = random_bytes(32);
+echo Encoding::base64Encode($data), "\n";
+echo Encoding::base32EncodeUpper($data), "\n";
+echo Encoding::base32Encode($data), "\n";
+echo Encoding::hexEncode($data), "\n";
+echo Encoding::hexEncodeUpper($data), "\n";
+```
+
+Example output:
+ 
+```
+1VilPkeVqirlPifk5scbzcTTbMT2clp+Zkyv9VFFasE=
+2VMKKPSHSWVCVZJ6E7SONRY3ZXCNG3GE6ZZFU7TGJSX7KUKFNLAQ====
+2vmkkpshswvcvzj6e7sonry3zxcng3ge6zzfu7tgjsx7kukfnlaq====
+d558a53e4795aa2ae53e27e4e6c71bcdc4d36cc4f6725a7e664caff551456ac1
+D558A53E4795AA2AE53E27E4E6C71BDCC4D36CC4F6725A7E664CAFF551456AC1
+```
+
+If you only need a particular variant, you can just reference the 
+required class like so:
+
+```php
+use \ParagonIE\ConstantTime\Base64;
+use \ParagonIE\ConstantTime\Base32;
+
+$data = random_bytes(32);
+echo Base64::encode($data), "\n";
+echo Base32::encode($data), "\n";
+```
+
+Example output:
+
+```
+1VilPkeVqirlPifk5scbzcTTbMT2clp+Zkyv9VFFasE=
+2vmkkpshswvcvzj6e7sonry3zxcng3ge6zzfu7tgjsx7kukfnlaq====
+```

+ 40 - 0
api/vendor/paragonie/constant_time_encoding/composer.json

@@ -0,0 +1,40 @@
+{
+  "name": "paragonie/constant_time_encoding",
+  "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
+  "keywords": [
+    "base64", "encoding", "rfc4648", "base32", "base16", "hex", "bin2hex", "hex2bin", "base64_encode", "base64_decode", "base32_encode", "base32_decode"
+  ],
+  "license": "MIT",
+  "type": "library",
+  "authors": [
+      {
+        "name":     "Paragon Initiative Enterprises",
+        "email":    "security@paragonie.com",
+        "homepage": "https://paragonie.com",
+        "role":     "Maintainer"
+      },
+      {
+        "name":     "Steve 'Sc00bz' Thomas",
+        "email":    "steve@tobtu.com",
+        "homepage": "https://www.tobtu.com",
+        "role":     "Original Developer"
+      }
+  ],
+  "support": {
+    "issues":   "https://github.com/paragonie/constant_time_encoding/issues",
+    "email":    "info@paragonie.com",
+    "source":   "https://github.com/paragonie/constant_time_encoding"
+  },
+  "require": {
+    "php": "^7"
+  },
+  "require-dev": {
+    "phpunit/phpunit": "^6|^7",
+    "vimeo/psalm": "^1"
+  },
+  "autoload": {
+    "psr-4": {
+      "ParagonIE\\ConstantTime\\": "src/"
+    }
+  }
+}

+ 29 - 0
api/vendor/paragonie/constant_time_encoding/phpunit.xml.dist

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit backupGlobals="true"
+         backupStaticAttributes="false"
+         bootstrap="vendor/autoload.php"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         stopOnError="false"
+         stopOnFailure="false"
+         syntaxCheck="true"
+>
+    <testsuites>
+        <testsuite name="Unit">
+            <directory>tests</directory>
+        </testsuite>
+    </testsuites>
+    <testsuites>
+        <testsuite name="Constant Time Encoding Test Suite">
+            <directory suffix="Test.php">./tests</directory>
+        </testsuite>
+    </testsuites>
+    <filter>
+        <whitelist processUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">./src</directory>
+        </whitelist>
+    </filter>
+</phpunit>

+ 10 - 0
api/vendor/paragonie/constant_time_encoding/psalm.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<psalm
+    stopOnFirstError="false"
+    useDocblockTypes="true"
+    totallyTyped="true"
+>
+    <projectFiles>
+        <directory name="src" />
+    </projectFiles>
+</psalm>

+ 468 - 0
api/vendor/paragonie/constant_time_encoding/src/Base32.php

@@ -0,0 +1,468 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Base32
+ * [A-Z][2-7]
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Base32 implements EncoderInterface
+{
+    /**
+     * Decode a Base32-encoded string into raw binary
+     *
+     * @param string $src
+     * @return string
+     * @throws \TypeError
+     */
+    public static function decode(string $src, bool $strictPadding = false): string
+    {
+        return static::doDecode($src, false, $strictPadding);
+    }
+
+    /**
+     * Decode an uppercase Base32-encoded string into raw binary
+     *
+     * @param string $src
+     * @return string
+     * @throws \TypeError
+     */
+    public static function decodeUpper(string $src, bool $strictPadding = false): string
+    {
+        return static::doDecode($src, true, $strictPadding);
+    }
+
+    /**
+     * Encode into Base32 (RFC 4648)
+     *
+     * @param string $src
+     * @return string
+     * @throws \TypeError
+     */
+    public static function encode(string $src): string
+    {
+        return static::doEncode($src, false, true);
+    }
+    /**
+     * Encode into Base32 (RFC 4648)
+     *
+     * @param string $src
+     * @return string
+     * @throws \TypeError
+     */
+    public static function encodeUnpadded(string $src): string
+    {
+        return static::doEncode($src, false, false);
+    }
+
+    /**
+     * Encode into uppercase Base32 (RFC 4648)
+     *
+     * @param string $src
+     * @return string
+     * @throws \TypeError
+     */
+    public static function encodeUpper(string $src): string
+    {
+        return static::doEncode($src, true, true);
+    }
+
+    /**
+     * Encode into uppercase Base32 (RFC 4648)
+     *
+     * @param string $src
+     * @return string
+     * @throws \TypeError
+     */
+    public static function encodeUpperUnpadded(string $src): string
+    {
+        return static::doEncode($src, true, false);
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
+     * into 8-bit integers.
+     *
+     * @param int $src
+     * @return int
+     */
+    protected static function decode5Bits(int $src): int
+    {
+        $ret = -1;
+
+        // if ($src > 96 && $src < 123) $ret += $src - 97 + 1; // -64
+        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 96);
+
+        // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
+        $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23);
+
+        return $ret;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
+     * into 8-bit integers.
+     *
+     * Uppercase variant.
+     *
+     * @param int $src
+     * @return int
+     */
+    protected static function decode5BitsUpper(int $src): int
+    {
+        $ret = -1;
+
+        // if ($src > 64 && $src < 91) $ret += $src - 65 + 1; // -64
+        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
+
+        // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
+        $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23);
+
+        return $ret;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
+     * into 5-bit integers.
+     *
+     * @param int $src
+     * @return string
+     */
+    protected static function encode5Bits(int $src): string
+    {
+        $diff = 0x61;
+
+        // if ($src > 25) $ret -= 72;
+        $diff -= ((25 - $src) >> 8) & 73;
+
+        return \pack('C', $src + $diff);
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
+     * into 5-bit integers.
+     *
+     * Uppercase variant.
+     *
+     * @param int $src
+     * @return string
+     */
+    protected static function encode5BitsUpper(int $src): string
+    {
+        $diff = 0x41;
+
+        // if ($src > 25) $ret -= 40;
+        $diff -= ((25 - $src) >> 8) & 41;
+
+        return \pack('C', $src + $diff);
+    }
+
+
+    /**
+     * Base32 decoding
+     *
+     * @param string $src
+     * @param bool $upper
+     * @param bool $strictPadding
+     * @return string
+     * @throws \TypeError
+     */
+    protected static function doDecode(string $src, bool $upper = false, bool $strictPadding = false): string
+    {
+        // We do this to reduce code duplication:
+        $method = $upper
+            ? 'decode5BitsUpper'
+            : 'decode5Bits';
+
+        // Remove padding
+        $srcLen = Binary::safeStrlen($src);
+        if ($srcLen === 0) {
+            return '';
+        }
+        if ($strictPadding) {
+            if (($srcLen & 7) === 0) {
+                for ($j = 0; $j < 7; ++$j) {
+                    if ($src[$srcLen - 1] === '=') {
+                        $srcLen--;
+                    } else {
+                        break;
+                    }
+                }
+            }
+            if (($srcLen & 7) === 1) {
+                throw new \RangeException(
+                    'Incorrect padding'
+                );
+            }
+        } else {
+            $src = \rtrim($src, '=');
+            $srcLen = Binary::safeStrlen($src);
+        }
+
+        $err = 0;
+        $dest = '';
+        // Main loop (no padding):
+        for ($i = 0; $i + 8 <= $srcLen; $i += 8) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 8));
+            /** @var int $c0 */
+            $c0 = static::$method($chunk[1]);
+            /** @var int $c1 */
+            $c1 = static::$method($chunk[2]);
+            /** @var int $c2 */
+            $c2 = static::$method($chunk[3]);
+            /** @var int $c3 */
+            $c3 = static::$method($chunk[4]);
+            /** @var int $c4 */
+            $c4 = static::$method($chunk[5]);
+            /** @var int $c5 */
+            $c5 = static::$method($chunk[6]);
+            /** @var int $c6 */
+            $c6 = static::$method($chunk[7]);
+            /** @var int $c7 */
+            $c7 = static::$method($chunk[8]);
+
+            $dest .= \pack(
+                'CCCCC',
+                (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
+                (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
+                (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
+                (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff,
+                (($c6 << 5) | ($c7     )             ) & 0xff
+            );
+            $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6 | $c7) >> 8;
+        }
+        // The last chunk, which may have padding:
+        if ($i < $srcLen) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
+            /** @var int $c0 */
+            $c0 = static::$method($chunk[1]);
+
+            if ($i + 6 < $srcLen) {
+                /** @var int $c1 */
+                $c1 = static::$method($chunk[2]);
+                /** @var int $c2 */
+                $c2 = static::$method($chunk[3]);
+                /** @var int $c3 */
+                $c3 = static::$method($chunk[4]);
+                /** @var int $c4 */
+                $c4 = static::$method($chunk[5]);
+                /** @var int $c5 */
+                $c5 = static::$method($chunk[6]);
+                /** @var int $c6 */
+                $c6 = static::$method($chunk[7]);
+
+                $dest .= \pack(
+                    'CCCC',
+                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
+                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
+                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
+                    (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff
+                );
+                $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8;
+            } elseif ($i + 5 < $srcLen) {
+                /** @var int $c1 */
+                $c1 = static::$method($chunk[2]);
+                /** @var int $c2 */
+                $c2 = static::$method($chunk[3]);
+                /** @var int $c3 */
+                $c3 = static::$method($chunk[4]);
+                /** @var int $c4 */
+                $c4 = static::$method($chunk[5]);
+                /** @var int $c5 */
+                $c5 = static::$method($chunk[6]);
+
+                $dest .= \pack(
+                    'CCCC',
+                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
+                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
+                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
+                    (($c4 << 7) | ($c5 << 2)             ) & 0xff
+                );
+                $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5) >> 8;
+            } elseif ($i + 4 < $srcLen) {
+                /** @var int $c1 */
+                $c1 = static::$method($chunk[2]);
+                /** @var int $c2 */
+                $c2 = static::$method($chunk[3]);
+                /** @var int $c3 */
+                $c3 = static::$method($chunk[4]);
+                /** @var int $c4 */
+                $c4 = static::$method($chunk[5]);
+
+                $dest .= \pack(
+                    'CCC',
+                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
+                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
+                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff
+                );
+                $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8;
+            } elseif ($i + 3 < $srcLen) {
+                /** @var int $c1 */
+                $c1 = static::$method($chunk[2]);
+                /** @var int $c2 */
+                $c2 = static::$method($chunk[3]);
+                /** @var int $c3 */
+                $c3 = static::$method($chunk[4]);
+
+                $dest .= \pack(
+                    'CC',
+                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
+                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff
+                );
+                $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
+            } elseif ($i + 2 < $srcLen) {
+                /** @var int $c1 */
+                $c1 = static::$method($chunk[2]);
+                /** @var int $c2 */
+                $c2 = static::$method($chunk[3]);
+
+                $dest .= \pack(
+                    'CC',
+                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
+                    (($c1 << 6) | ($c2 << 1)             ) & 0xff
+                );
+                $err |= ($c0 | $c1 | $c2) >> 8;
+            } elseif ($i + 1 < $srcLen) {
+                /** @var int $c1 */
+                $c1 = static::$method($chunk[2]);
+
+                $dest .= \pack(
+                    'C',
+                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff
+                );
+                $err |= ($c0 | $c1) >> 8;
+            } else {
+                $dest .= \pack(
+                    'C',
+                    (($c0 << 3)                          ) & 0xff
+                );
+                $err |= ($c0) >> 8;
+            }
+        }
+        if ($err !== 0) {
+            throw new \RangeException(
+                'Base32::doDecode() only expects characters in the correct base32 alphabet'
+            );
+        }
+        return $dest;
+    }
+
+    /**
+     * Base32 Decoding
+     *
+     * @param string $src
+     * @param bool $upper
+     * @param bool $pad
+     * @return string
+     * @throws \TypeError
+     */
+    protected static function doEncode(string $src, bool $upper = false, $pad = true): string
+    {
+        // We do this to reduce code duplication:
+        $method = $upper
+            ? 'encode5BitsUpper'
+            : 'encode5Bits';
+        
+        $dest = '';
+        $srcLen = Binary::safeStrlen($src);
+
+        // Main loop (no padding):
+        for ($i = 0; $i + 5 <= $srcLen; $i += 5) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 5));
+            $b0 = $chunk[1];
+            $b1 = $chunk[2];
+            $b2 = $chunk[3];
+            $b3 = $chunk[4];
+            $b4 = $chunk[5];
+            $dest .=
+                static::$method(              ($b0 >> 3)  & 31) .
+                static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
+                static::$method((($b1 >> 1)             ) & 31) .
+                static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
+                static::$method((($b2 << 1) | ($b3 >> 7)) & 31) .
+                static::$method((($b3 >> 2)             ) & 31) .
+                static::$method((($b3 << 3) | ($b4 >> 5)) & 31) .
+                static::$method(  $b4                     & 31);
+        }
+        // The last chunk, which may have padding:
+        if ($i < $srcLen) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
+            $b0 = $chunk[1];
+            if ($i + 3 < $srcLen) {
+                $b1 = $chunk[2];
+                $b2 = $chunk[3];
+                $b3 = $chunk[4];
+                $dest .=
+                    static::$method(              ($b0 >> 3)  & 31) .
+                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
+                    static::$method((($b1 >> 1)             ) & 31) .
+                    static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
+                    static::$method((($b2 << 1) | ($b3 >> 7)) & 31) .
+                    static::$method((($b3 >> 2)             ) & 31) .
+                    static::$method((($b3 << 3)             ) & 31);
+                if ($pad) {
+                    $dest .= '=';
+                }
+            } elseif ($i + 2 < $srcLen) {
+                $b1 = $chunk[2];
+                $b2 = $chunk[3];
+                $dest .=
+                    static::$method(              ($b0 >> 3)  & 31) .
+                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
+                    static::$method((($b1 >> 1)             ) & 31) .
+                    static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
+                    static::$method((($b2 << 1)             ) & 31);
+                if ($pad) {
+                    $dest .= '===';
+                }
+            } elseif ($i + 1 < $srcLen) {
+                $b1 = $chunk[2];
+                $dest .=
+                    static::$method(              ($b0 >> 3)  & 31) .
+                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
+                    static::$method((($b1 >> 1)             ) & 31) .
+                    static::$method((($b1 << 4)             ) & 31);
+                if ($pad) {
+                    $dest .= '====';
+                }
+            } else {
+                $dest .=
+                    static::$method(              ($b0 >> 3)  & 31) .
+                    static::$method( ($b0 << 2)               & 31);
+                if ($pad) {
+                    $dest .= '======';
+                }
+            }
+        }
+        return $dest;
+    }
+}

+ 111 - 0
api/vendor/paragonie/constant_time_encoding/src/Base32Hex.php

@@ -0,0 +1,111 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Base32Hex
+ * [0-9][A-V]
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Base32Hex extends Base32
+{
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
+     * into 8-bit integers.
+     *
+     * @param int $src
+     * @return int
+     */
+    protected static function decode5Bits(int $src): int
+    {
+        $ret = -1;
+
+        // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
+        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47);
+
+        // if ($src > 0x60 && $src < 0x77) ret += $src - 0x61 + 10 + 1; // -86
+        $ret += (((0x60 - $src) & ($src - 0x77)) >> 8) & ($src - 86);
+
+        return $ret;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
+     * into 8-bit integers.
+     *
+     * @param int $src
+     * @return int
+     */
+    protected static function decode5BitsUpper(int $src): int
+    {
+        $ret = -1;
+
+        // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
+        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47);
+
+        // if ($src > 0x40 && $src < 0x57) ret += $src - 0x41 + 10 + 1; // -54
+        $ret += (((0x40 - $src) & ($src - 0x57)) >> 8) & ($src - 54);
+
+        return $ret;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
+     * into 5-bit integers.
+     *
+     * @param int $src
+     * @return string
+     */
+    protected static function encode5Bits(int $src): string
+    {
+        $src += 0x30;
+
+        // if ($src > 0x39) $src += 0x61 - 0x3a; // 39
+        $src += ((0x39 - $src) >> 8) & 39;
+
+        return \pack('C', $src);
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
+     * into 5-bit integers.
+     *
+     * Uppercase variant.
+     *
+     * @param int $src
+     * @return string
+     */
+    protected static function encode5BitsUpper(int $src): string
+    {
+        $src += 0x30;
+
+        // if ($src > 0x39) $src += 0x41 - 0x3a; // 7
+        $src += ((0x39 - $src) >> 8) & 7;
+
+        return \pack('C', $src);
+    }
+}

+ 268 - 0
api/vendor/paragonie/constant_time_encoding/src/Base64.php

@@ -0,0 +1,268 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Base64
+ * [A-Z][a-z][0-9]+/
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Base64 implements EncoderInterface
+{
+    /**
+     * Encode into Base64
+     *
+     * Base64 character set "[A-Z][a-z][0-9]+/"
+     *
+     * @param string $src
+     * @return string
+     * @throws \TypeError
+     */
+    public static function encode(string $src): string
+    {
+        return static::doEncode($src, true);
+    }
+
+    /**
+     * Encode into Base64, no = padding
+     *
+     * Base64 character set "[A-Z][a-z][0-9]+/"
+     *
+     * @param string $src
+     * @return string
+     * @throws \TypeError
+     */
+    public static function encodeUnpadded(string $src): string
+    {
+        return static::doEncode($src, false);
+    }
+
+    /**
+     * @param string $src
+     * @param bool $pad   Include = padding?
+     * @return string
+     * @throws \TypeError
+     */
+    protected static function doEncode(string $src, bool $pad = true): string
+    {
+        $dest = '';
+        $srcLen = Binary::safeStrlen($src);
+        // Main loop (no padding):
+        for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 3));
+            $b0 = $chunk[1];
+            $b1 = $chunk[2];
+            $b2 = $chunk[3];
+
+            $dest .=
+                static::encode6Bits(               $b0 >> 2       ) .
+                static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
+                static::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
+                static::encode6Bits(  $b2                     & 63);
+        }
+        // The last chunk, which may have padding:
+        if ($i < $srcLen) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
+            $b0 = $chunk[1];
+            if ($i + 1 < $srcLen) {
+                $b1 = $chunk[2];
+                $dest .=
+                    static::encode6Bits($b0 >> 2) .
+                    static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
+                    static::encode6Bits(($b1 << 2) & 63);
+                if ($pad) {
+                    $dest .= '=';
+                }
+            } else {
+                $dest .=
+                    static::encode6Bits( $b0 >> 2) .
+                    static::encode6Bits(($b0 << 4) & 63);
+                if ($pad) {
+                    $dest .= '==';
+                }
+            }
+        }
+        return $dest;
+    }
+
+    /**
+     * decode from base64 into binary
+     *
+     * Base64 character set "./[A-Z][a-z][0-9]"
+     *
+     * @param string $src
+     * @param bool $strictPadding
+     * @return string
+     * @throws \RangeException
+     * @throws \TypeError
+     */
+    public static function decode(string $src, bool $strictPadding = false): string
+    {
+        // Remove padding
+        $srcLen = Binary::safeStrlen($src);
+        if ($srcLen === 0) {
+            return '';
+        }
+
+        if ($strictPadding) {
+            if (($srcLen & 3) === 0) {
+                if ($src[$srcLen - 1] === '=') {
+                    $srcLen--;
+                    if ($src[$srcLen - 1] === '=') {
+                        $srcLen--;
+                    }
+                }
+            }
+            if (($srcLen & 3) === 1) {
+                throw new \RangeException(
+                    'Incorrect padding'
+                );
+            }
+            if ($src[$srcLen - 1] === '=') {
+                throw new \RangeException(
+                    'Incorrect padding'
+                );
+            }
+        } else {
+            $src = \rtrim($src, '=');
+            $srcLen = Binary::safeStrlen($src);
+        }
+
+        $err = 0;
+        $dest = '';
+        // Main loop (no padding):
+        for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 4));
+            $c0 = static::decode6Bits($chunk[1]);
+            $c1 = static::decode6Bits($chunk[2]);
+            $c2 = static::decode6Bits($chunk[3]);
+            $c3 = static::decode6Bits($chunk[4]);
+
+            $dest .= \pack(
+                'CCC',
+                ((($c0 << 2) | ($c1 >> 4)) & 0xff),
+                ((($c1 << 4) | ($c2 >> 2)) & 0xff),
+                ((($c2 << 6) |  $c3      ) & 0xff)
+            );
+            $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
+        }
+        // The last chunk, which may have padding:
+        if ($i < $srcLen) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
+            $c0 = static::decode6Bits($chunk[1]);
+
+            if ($i + 2 < $srcLen) {
+                $c1 = static::decode6Bits($chunk[2]);
+                $c2 = static::decode6Bits($chunk[3]);
+                $dest .= \pack(
+                    'CC',
+                    ((($c0 << 2) | ($c1 >> 4)) & 0xff),
+                    ((($c1 << 4) | ($c2 >> 2)) & 0xff)
+                );
+                $err |= ($c0 | $c1 | $c2) >> 8;
+            } elseif ($i + 1 < $srcLen) {
+                $c1 = static::decode6Bits($chunk[2]);
+                $dest .= \pack(
+                    'C',
+                    ((($c0 << 2) | ($c1 >> 4)) & 0xff)
+                );
+                $err |= ($c0 | $c1) >> 8;
+            } elseif ($i < $srcLen && $strictPadding) {
+                $err |= 1;
+            }
+        }
+        if ($err !== 0) {
+            throw new \RangeException(
+                'Base64::decode() only expects characters in the correct base64 alphabet'
+            );
+        }
+        return $dest;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
+     * into 8-bit integers.
+     *
+     * Base64 character set:
+     * [A-Z]      [a-z]      [0-9]      +     /
+     * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
+     *
+     * @param int $src
+     * @return int
+     */
+    protected static function decode6Bits(int $src): int
+    {
+        $ret = -1;
+
+        // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
+        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
+
+        // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
+        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);
+
+        // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
+        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);
+
+        // if ($src == 0x2b) $ret += 62 + 1;
+        $ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63;
+
+        // if ($src == 0x2f) ret += 63 + 1;
+        $ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64;
+
+        return $ret;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
+     * into 6-bit integers.
+     *
+     * @param int $src
+     * @return string
+     */
+    protected static function encode6Bits(int $src): string
+    {
+        $diff = 0x41;
+
+        // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
+        $diff += ((25 - $src) >> 8) & 6;
+
+        // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
+        $diff -= ((51 - $src) >> 8) & 75;
+
+        // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
+        $diff -= ((61 - $src) >> 8) & 15;
+
+        // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
+        $diff += ((62 - $src) >> 8) & 3;
+
+        return \pack('C', $src + $diff);
+    }
+}

+ 88 - 0
api/vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php

@@ -0,0 +1,88 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Base64DotSlash
+ * ./[A-Z][a-z][0-9]
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Base64DotSlash extends Base64
+{
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
+     * into 8-bit integers.
+     *
+     * Base64 character set:
+     * ./         [A-Z]      [a-z]     [0-9]
+     * 0x2e-0x2f, 0x41-0x5a, 0x61-0x7a, 0x30-0x39
+     *
+     * @param int $src
+     * @return int
+     */
+    protected static function decode6Bits(int $src): int
+    {
+        $ret = -1;
+
+        // if ($src > 0x2d && $src < 0x30) ret += $src - 0x2e + 1; // -45
+        $ret += (((0x2d - $src) & ($src - 0x30)) >> 8) & ($src - 45);
+
+        // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 2 + 1; // -62
+        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 62);
+
+        // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 28 + 1; // -68
+        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 68);
+
+        // if ($src > 0x2f && $src < 0x3a) ret += $src - 0x30 + 54 + 1; // 7
+        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 7);
+
+        return $ret;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
+     * into 6-bit integers.
+     *
+     * @param int $src
+     * @return string
+     */
+    protected static function encode6Bits(int $src): string
+    {
+        $src += 0x2e;
+
+        // if ($src > 0x2f) $src += 0x41 - 0x30; // 17
+        $src += ((0x2f - $src) >> 8) & 17;
+
+        // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6
+        $src += ((0x5a - $src) >> 8) & 6;
+
+        // if ($src > 0x7a) $src += 0x30 - 0x7b; // -75
+        $src -= ((0x7a - $src) >> 8) & 75;
+
+        return \pack('C', $src);
+    }
+}

+ 82 - 0
api/vendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php

@@ -0,0 +1,82 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Base64DotSlashOrdered
+ * ./[0-9][A-Z][a-z]
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Base64DotSlashOrdered extends Base64
+{
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
+     * into 8-bit integers.
+     *
+     * Base64 character set:
+     * [.-9]      [A-Z]      [a-z]
+     * 0x2e-0x39, 0x41-0x5a, 0x61-0x7a
+     *
+     * @param int $src
+     * @return int
+     */
+    protected static function decode6Bits(int $src): int
+    {
+        $ret = -1;
+
+        // if ($src > 0x2d && $src < 0x3a) ret += $src - 0x2e + 1; // -45
+        $ret += (((0x2d - $src) & ($src - 0x3a)) >> 8) & ($src - 45);
+
+        // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 12 + 1; // -52
+        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 52);
+
+        // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 38 + 1; // -58
+        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 58);
+
+        return $ret;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
+     * into 6-bit integers.
+     *
+     * @param int $src
+     * @return string
+     */
+    protected static function encode6Bits(int $src): string
+    {
+        $src += 0x2e;
+
+        // if ($src > 0x39) $src += 0x41 - 0x3a; // 7
+        $src += ((0x39 - $src) >> 8) & 7;
+
+        // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6
+        $src += ((0x5a - $src) >> 8) & 6;
+
+        return \pack('C', $src);
+    }
+}

+ 95 - 0
api/vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php

@@ -0,0 +1,95 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Base64UrlSafe
+ * [A-Z][a-z][0-9]\-_
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Base64UrlSafe extends Base64
+{
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
+     * into 8-bit integers.
+     *
+     * Base64 character set:
+     * [A-Z]      [a-z]      [0-9]      -     _
+     * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2d, 0x5f
+     *
+     * @param int $src
+     * @return int
+     */
+    protected static function decode6Bits(int $src): int
+    {
+        $ret = -1;
+
+        // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
+        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
+
+        // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
+        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);
+
+        // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
+        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);
+
+        // if ($src == 0x2c) $ret += 62 + 1;
+        $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63;
+
+        // if ($src == 0x5f) ret += 63 + 1;
+        $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64;
+
+        return $ret;
+    }
+
+    /**
+     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
+     * into 6-bit integers.
+     *
+     * @param int $src
+     * @return string
+     */
+    protected static function encode6Bits(int $src): string
+    {
+        $diff = 0x41;
+
+        // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
+        $diff += ((25 - $src) >> 8) & 6;
+
+        // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
+        $diff -= ((51 - $src) >> 8) & 75;
+
+        // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
+        $diff -= ((61 - $src) >> 8) & 13;
+
+        // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
+        $diff += ((62 - $src) >> 8) & 49;
+
+        return \pack('C', $src + $diff);
+    }
+}

+ 85 - 0
api/vendor/paragonie/constant_time_encoding/src/Binary.php

@@ -0,0 +1,85 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Binary
+ *
+ * Binary string operators that don't choke on
+ * mbstring.func_overload
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Binary
+{
+    /**
+     * Safe string length
+     *
+     * @ref mbstring.func_overload
+     *
+     * @param string $str
+     * @return int
+     */
+    public static function safeStrlen(string $str): int
+    {
+        if (\function_exists('mb_strlen')) {
+            return (int) \mb_strlen($str, '8bit');
+        } else {
+            return (int) \strlen($str);
+        }
+    }
+
+    /**
+     * Safe substring
+     *
+     * @ref mbstring.func_overload
+     *
+     * @staticvar boolean $exists
+     * @param string $str
+     * @param int $start
+     * @param int $length
+     * @return string
+     * @throws \TypeError
+     */
+    public static function safeSubstr(
+        string $str,
+        int $start = 0,
+        $length = null
+    ): string {
+        if ($length === 0) {
+            return '';
+        }
+        if (\function_exists('mb_substr')) {
+            return \mb_substr($str, $start, $length, '8bit');
+        }
+        // Unlike mb_substr(), substr() doesn't accept NULL for length
+        if ($length !== null) {
+            return \substr($str, $start, $length);
+        } else {
+            return \substr($str, $start);
+        }
+    }
+}

+ 52 - 0
api/vendor/paragonie/constant_time_encoding/src/EncoderInterface.php

@@ -0,0 +1,52 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Interface EncoderInterface
+ * @package ParagonIE\ConstantTime
+ */
+interface EncoderInterface
+{
+    /**
+     * Convert a binary string into a hexadecimal string without cache-timing
+     * leaks
+     *
+     * @param string $binString (raw binary)
+     * @return string
+     */
+    public static function encode(string $binString): string;
+
+    /**
+     * Convert a binary string into a hexadecimal string without cache-timing
+     * leaks
+     *
+     * @param string $encodedString
+     * @param bool $strictPadding Error on invalid padding
+     * @return string (raw binary)
+     */
+    public static function decode(string $encodedString, bool $strictPadding = false): string;
+}

+ 260 - 0
api/vendor/paragonie/constant_time_encoding/src/Encoding.php

@@ -0,0 +1,260 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Encoding
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Encoding
+{
+    /**
+     * RFC 4648 Base32 encoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base32Encode(string $str): string
+    {
+        return Base32::encode($str);
+    }
+
+    /**
+     * RFC 4648 Base32 encoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base32EncodeUpper(string $str): string
+    {
+        return Base32::encodeUpper($str);
+    }
+
+    /**
+     * RFC 4648 Base32 decoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base32Decode(string $str): string
+    {
+        return Base32::decode($str);
+    }
+
+    /**
+     * RFC 4648 Base32 decoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base32DecodeUpper(string $str): string
+    {
+        return Base32::decodeUpper($str);
+    }
+
+    /**
+     * RFC 4648 Base32 encoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base32HexEncode(string $str): string
+    {
+        return Base32Hex::encode($str);
+    }
+
+    /**
+     * RFC 4648 Base32Hex encoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base32HexEncodeUpper(string $str): string
+    {
+        return Base32Hex::encodeUpper($str);
+    }
+
+    /**
+     * RFC 4648 Base32Hex decoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base32HexDecode(string $str): string
+    {
+        return Base32Hex::decode($str);
+    }
+
+    /**
+     * RFC 4648 Base32Hex decoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base32HexDecodeUpper(string $str): string
+    {
+        return Base32Hex::decodeUpper($str);
+    }
+
+    /**
+     * RFC 4648 Base64 encoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base64Encode(string $str): string
+    {
+        return Base64::encode($str);
+    }
+
+    /**
+     * RFC 4648 Base64 decoding
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base64Decode(string $str): string
+    {
+        return Base64::decode($str);
+    }
+
+    /**
+     * Encode into Base64
+     *
+     * Base64 character set "./[A-Z][a-z][0-9]"
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base64EncodeDotSlash(string $str): string
+    {
+        return Base64DotSlash::encode($str);
+    }
+
+    /**
+     * Decode from base64 to raw binary
+     *
+     * Base64 character set "./[A-Z][a-z][0-9]"
+     *
+     * @param string $str
+     * @return string
+     * @throws \RangeException
+     * @throws \TypeError
+     */
+    public static function base64DecodeDotSlash(string $str): string
+    {
+        return Base64DotSlash::decode($str);
+    }
+
+    /**
+     * Encode into Base64
+     *
+     * Base64 character set "[.-9][A-Z][a-z]" or "./[0-9][A-Z][a-z]"
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public static function base64EncodeDotSlashOrdered(string $str): string
+    {
+        return Base64DotSlashOrdered::encode($str);
+    }
+
+    /**
+     * Decode from base64 to raw binary
+     *
+     * Base64 character set "[.-9][A-Z][a-z]" or "./[0-9][A-Z][a-z]"
+     *
+     * @param string $str
+     * @return string
+     * @throws \RangeException
+     * @throws \TypeError
+     */
+    public static function base64DecodeDotSlashOrdered(string $str): string
+    {
+        return Base64DotSlashOrdered::decode($str);
+    }
+
+    /**
+     * Convert a binary string into a hexadecimal string without cache-timing
+     * leaks
+     *
+     * @param string $bin_string (raw binary)
+     * @return string
+     * @throws \TypeError
+     */
+    public static function hexEncode(string $bin_string): string
+    {
+        return Hex::encode($bin_string);
+    }
+
+    /**
+     * Convert a hexadecimal string into a binary string without cache-timing
+     * leaks
+     *
+     * @param string $hex_string
+     * @return string (raw binary)
+     * @throws \RangeException
+     */
+    public static function hexDecode(string $hex_string): string
+    {
+        return Hex::decode($hex_string);
+    }
+
+    /**
+     * Convert a binary string into a hexadecimal string without cache-timing
+     * leaks
+     *
+     * @param string $bin_string (raw binary)
+     * @return string
+     * @throws \TypeError
+     */
+    public static function hexEncodeUpper(string $bin_string): string
+    {
+        return Hex::encodeUpper($bin_string);
+    }
+
+    /**
+     * Convert a binary string into a hexadecimal string without cache-timing
+     * leaks
+     *
+     * @param string $bin_string (raw binary)
+     * @return string
+     */
+    public static function hexDecodeUpper(string $bin_string): string
+    {
+        return Hex::decode($bin_string);
+    }
+}

+ 159 - 0
api/vendor/paragonie/constant_time_encoding/src/Hex.php

@@ -0,0 +1,159 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class Hex
+ * @package ParagonIE\ConstantTime
+ */
+abstract class Hex implements EncoderInterface
+{
+    /**
+     * Convert a binary string into a hexadecimal string without cache-timing
+     * leaks
+     *
+     * @param string $binString (raw binary)
+     * @return string
+     * @throws \TypeError
+     */
+    public static function encode(string $binString): string
+    {
+        /** @var string $hex */
+        $hex = '';
+        $len = Binary::safeStrlen($binString);
+        for ($i = 0; $i < $len; ++$i) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C', Binary::safeSubstr($binString, $i, 1));
+            /** @var int $c */
+            $c = $chunk[1] & 0xf;
+            /** @var int $b */
+            $b = $chunk[1] >> 4;
+
+            $hex .= pack(
+                'CC',
+                (87 + $b + ((($b - 10) >> 8) & ~38)),
+                (87 + $c + ((($c - 10) >> 8) & ~38))
+            );
+        }
+        return $hex;
+    }
+
+    /**
+     * Convert a binary string into a hexadecimal string without cache-timing
+     * leaks, returning uppercase letters (as per RFC 4648)
+     *
+     * @param string $binString (raw binary)
+     * @return string
+     * @throws \TypeError
+     */
+    public static function encodeUpper(string $binString): string
+    {
+        /** @var string $hex */
+        $hex = '';
+        /** @var int $len */
+        $len = Binary::safeStrlen($binString);
+
+        for ($i = 0; $i < $len; ++$i) {
+            /** @var array<int, int> $chunk */
+            $chunk = \unpack('C', Binary::safeSubstr($binString, $i, 2));
+            /** @var int $c */
+            $c = $chunk[1] & 0xf;
+            /** @var int $b */
+            $b = $chunk[1] >> 4;
+
+            $hex .= pack(
+                'CC',
+                (55 + $b + ((($b - 10) >> 8) & ~6)),
+                (55 + $c + ((($c - 10) >> 8) & ~6))
+            );
+        }
+        return $hex;
+    }
+
+    /**
+     * Convert a hexadecimal string into a binary string without cache-timing
+     * leaks
+     *
+     * @param string $hexString
+     * @param bool $strictPadding
+     * @return string (raw binary)
+     * @throws \RangeException
+     */
+    public static function decode(string $hexString, bool $strictPadding = false): string
+    {
+        /** @var int $hex_pos */
+        $hex_pos = 0;
+        /** @var string $bin */
+        $bin = '';
+        /** @var int $c_acc */
+        $c_acc = 0;
+        /** @var int $hex_len */
+        $hex_len = Binary::safeStrlen($hexString);
+        /** @var int $state */
+        $state = 0;
+        if (($hex_len & 1) !== 0) {
+            if ($strictPadding) {
+                throw new \RangeException(
+                    'Expected an even number of hexadecimal characters'
+                );
+            } else {
+                $hexString = '0' . $hexString;
+                ++$hex_len;
+            }
+        }
+
+        /** @var array<int, ing> $chunk */
+        $chunk = \unpack('C*', $hexString);
+        while ($hex_pos < $hex_len) {
+            ++$hex_pos;
+            /** @var int $c */
+            $c = $chunk[$hex_pos];
+            /** @var int $c_num */
+            $c_num = $c ^ 48;
+            /** @var int $c_num0 */
+            $c_num0 = ($c_num - 10) >> 8;
+            /** @var int $c_alpha */
+            $c_alpha = ($c & ~32) - 55;
+            /** @var int $c_alpha0 */
+            $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
+
+            if (($c_num0 | $c_alpha0) === 0) {
+                throw new \RangeException(
+                    'hexEncode() only expects hexadecimal characters'
+                );
+            }
+            /** @var int $c_val */
+            $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
+            if ($state === 0) {
+                $c_acc = $c_val * 16;
+            } else {
+                $bin .= \pack('C', $c_acc | $c_val);
+            }
+            $state ^= 1;
+        }
+        return $bin;
+    }
+}

+ 175 - 0
api/vendor/paragonie/constant_time_encoding/src/RFC4648.php

@@ -0,0 +1,175 @@
+<?php
+declare(strict_types=1);
+namespace ParagonIE\ConstantTime;
+
+/**
+ *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
+ *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+/**
+ * Class RFC4648
+ *
+ * This class conforms strictly to the RFC
+ *
+ * @package ParagonIE\ConstantTime
+ */
+abstract class RFC4648
+{
+    /**
+     * RFC 4648 Base64 encoding
+     *
+     * "foo" -> "Zm9v"
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base64Encode(string $str): string
+    {
+        return Base64::encode($str);
+    }
+
+    /**
+     * RFC 4648 Base64 decoding
+     *
+     * "Zm9v" -> "foo"
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base64Decode(string $str): string
+    {
+        return Base64::decode($str, true);
+    }
+
+    /**
+     * RFC 4648 Base64 (URL Safe) encoding
+     *
+     * "foo" -> "Zm9v"
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base64UrlSafeEncode(string $str): string
+    {
+        return Base64UrlSafe::encode($str);
+    }
+
+    /**
+     * RFC 4648 Base64 (URL Safe) decoding
+     *
+     * "Zm9v" -> "foo"
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base64UrlSafeDecode(string $str): string
+    {
+        return Base64UrlSafe::decode($str, true);
+    }
+
+    /**
+     * RFC 4648 Base32 encoding
+     *
+     * "foo" -> "MZXW6==="
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base32Encode(string $str): string
+    {
+        return Base32::encodeUpper($str);
+    }
+
+    /**
+     * RFC 4648 Base32 encoding
+     *
+     * "MZXW6===" -> "foo"
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base32Decode(string $str): string
+    {
+        return Base32::decodeUpper($str, true);
+    }
+
+    /**
+     * RFC 4648 Base32-Hex encoding
+     *
+     * "foo" -> "CPNMU==="
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base32HexEncode(string $str): string
+    {
+        return Base32::encodeUpper($str);
+    }
+
+    /**
+     * RFC 4648 Base32-Hex decoding
+     *
+     * "CPNMU===" -> "foo"
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base32HexDecode(string $str): string
+    {
+        return Base32::decodeUpper($str, true);
+    }
+
+    /**
+     * RFC 4648 Base16 decoding
+     *
+     * "foo" -> "666F6F"
+     *
+     * @param string $str
+     * @return string
+     * @throws \TypeError
+     */
+    public function base16Encode(string $str): string
+    {
+        return Hex::encodeUpper($str);
+    }
+
+    /**
+     * RFC 4648 Base16 decoding
+     *
+     * "666F6F" -> "foo"
+     *
+     * @param string $str
+     * @return string
+     */
+    public function base16Decode(string $str): string
+    {
+        return Hex::decode($str, true);
+    }
+}

+ 49 - 0
api/vendor/paragonie/constant_time_encoding/tests/Base32HexTest.php

@@ -0,0 +1,49 @@
+<?php
+use \ParagonIE\ConstantTime\Base32Hex;
+
+class Base32HexTest extends PHPUnit\Framework\TestCase
+{
+    /**
+     * @covers Base32Hex::encode()
+     * @covers Base32Hex::decode()
+     * @covers Base32Hex::encodeUpper()
+     * @covers Base32Hex::decodeUpper()
+     */
+    public function testRandom()
+    {
+        for ($i = 1; $i < 32; ++$i) {
+            for ($j = 0; $j < 50; ++$j) {
+                $random = \random_bytes($i);
+
+                $enc = Base32Hex::encode($random);
+                $this->assertSame(
+                    $random,
+                    Base32Hex::decode($enc)
+                );
+                $unpadded = \rtrim($enc, '=');
+                $this->assertSame(
+                    $unpadded,
+                    Base32Hex::encodeUnpadded($random)
+                );
+                $this->assertSame(
+                    $random,
+                    Base32Hex::decode($unpadded)
+                );
+
+                $enc = Base32Hex::encodeUpper($random);
+                $this->assertSame(
+                    $random,
+                    Base32Hex::decodeUpper($enc)
+                );                $unpadded = \rtrim($enc, '=');
+                $this->assertSame(
+                    $unpadded,
+                    Base32Hex::encodeUpperUnpadded($random)
+                );
+                $this->assertSame(
+                    $random,
+                    Base32Hex::decodeUpper($unpadded)
+                );
+            }
+        }
+    }
+}

+ 50 - 0
api/vendor/paragonie/constant_time_encoding/tests/Base32Test.php

@@ -0,0 +1,50 @@
+<?php
+use \ParagonIE\ConstantTime\Base32;
+
+class Base32Test extends PHPUnit\Framework\TestCase
+{
+    /**
+     * @covers Base32::encode()
+     * @covers Base32::decode()
+     * @covers Base32::encodeUpper()
+     * @covers Base32::decodeUpper()
+     */
+    public function testRandom()
+    {
+        for ($i = 1; $i < 32; ++$i) {
+            for ($j = 0; $j < 50; ++$j) {
+                $random = \random_bytes($i);
+
+                $enc = Base32::encode($random);
+                $this->assertSame(
+                    $random,
+                    Base32::decode($enc)
+                );
+                $unpadded = \rtrim($enc, '=');
+                $this->assertSame(
+                    $unpadded,
+                    Base32::encodeUnpadded($random)
+                );
+                $this->assertSame(
+                    $random,
+                    Base32::decode($unpadded)
+                );
+
+                $enc = Base32::encodeUpper($random);
+                $this->assertSame(
+                    $random,
+                    Base32::decodeUpper($enc)
+                );
+                $unpadded = \rtrim($enc, '=');
+                $this->assertSame(
+                    $unpadded,
+                    Base32::encodeUpperUnpadded($random)
+                );
+                $this->assertSame(
+                    $random,
+                    Base32::decodeUpper($unpadded)
+                );
+            }
+        }
+    }
+}

+ 34 - 0
api/vendor/paragonie/constant_time_encoding/tests/Base64DotSlashOrderedTest.php

@@ -0,0 +1,34 @@
+<?php
+use \ParagonIE\ConstantTime\Base64DotSlashOrdered;
+
+class Base64DotSlashOrderedTest extends PHPUnit\Framework\TestCase
+{
+    /**
+     * @covers Base64DotSlashOrdered::encode()
+     * @covers Base64DotSlashOrdered::decode()
+     */
+    public function testRandom()
+    {
+        for ($i = 1; $i < 32; ++$i) {
+            for ($j = 0; $j < 50; ++$j) {
+                $random = \random_bytes($i);
+
+                $enc = Base64DotSlashOrdered::encode($random);
+                $this->assertSame(
+                    $random,
+                    Base64DotSlashOrdered::decode($enc)
+                );
+
+                $unpadded = \rtrim($enc, '=');
+                $this->assertSame(
+                    $random,
+                    Base64DotSlashOrdered::decode($unpadded)
+                );
+                $this->assertSame(
+                    $random,
+                    Base64DotSlashOrdered::decode($unpadded)
+                );
+            }
+        }
+    }
+}

+ 34 - 0
api/vendor/paragonie/constant_time_encoding/tests/Base64DotSlashTest.php

@@ -0,0 +1,34 @@
+<?php
+use \ParagonIE\ConstantTime\Base64DotSlash;
+
+class Base64DotSlashTest extends PHPUnit\Framework\TestCase
+{
+    /**
+     * @covers Base64DotSlash::encode()
+     * @covers Base64DotSlash::decode()
+     */
+    public function testRandom()
+    {
+        for ($i = 1; $i < 32; ++$i) {
+            for ($j = 0; $j < 50; ++$j) {
+                $random = \random_bytes($i);
+
+                $enc = Base64DotSlash::encode($random);
+                $this->assertSame(
+                    $random,
+                    Base64DotSlash::decode($enc)
+                );
+
+                $unpadded = \rtrim($enc, '=');
+                $this->assertSame(
+                    $random,
+                    Base64DotSlash::decode($unpadded)
+                );
+                $this->assertSame(
+                    $random,
+                    Base64DotSlash::decode($unpadded)
+                );
+            }
+        }
+    }
+}

+ 79 - 0
api/vendor/paragonie/constant_time_encoding/tests/Base64Test.php

@@ -0,0 +1,79 @@
+<?php
+use \ParagonIE\ConstantTime\Base64;
+
+class Base64Test extends PHPUnit\Framework\TestCase
+{
+    /**
+     * @covers Base64::encode()
+     * @covers Base64::decode()
+     */
+    public function testRandom()
+    {
+        for ($i = 1; $i < 32; ++$i) {
+            for ($j = 0; $j < 50; ++$j) {
+                $random = \random_bytes($i);
+
+                $enc = Base64::encode($random);
+                $this->assertSame(
+                    $random,
+                    Base64::decode($enc)
+                );
+                $this->assertSame(
+                    \base64_encode($random),
+                    $enc
+                );
+
+                $unpadded = \rtrim($enc, '=');
+                $this->assertSame(
+                    $random,
+                    Base64::decode($unpadded)
+                );
+                $this->assertSame(
+                    $random,
+                    Base64::decode($unpadded)
+                );
+            }
+        }
+        $str = 'MIIFzzCCBLegAwIBAgIDAfdlMA0GCSqGSIb3DQEBBQUAMHMxCzAJBgNVBAYTAlBM' .
+            'MSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMSQwIgYDVQQ' .
+            'DDBtDT1BFIFNaQUZJUiAtIEt3YWxpZmlrb3dhbnkxFDASBgNVBAUTC05yIHdwaXN1Oi' .
+            'A2MB4XDTExMTEwOTA2MDAwMFoXDTEzMTEwOTA2MDAwMFowgdkxCzAJBgNVBAYTAlBMM' .
+            'RwwGgYDVQQKDBNVcnrEhWQgTWlhc3RhIEdkeW5pMRswGQYDVQQFExJQRVNFTDogNjEw' .
+            'NjA2MDMxMTgxGTAXBgNVBAMMEEplcnp5IFByemV3b3Jza2kxTzBNBgNVBBAwRgwiQWw' .
+            'uIE1hcnN6YcWCa2EgUGnFgnN1ZHNraWVnbyA1Mi81NAwNODEtMzgyIEdkeW5pYQwGUG' .
+            '9sc2thDAlwb21vcnNraWUxDjAMBgNVBCoMBUplcnp5MRMwEQYDVQQEDApQcnpld29yc' .
+            '2tpMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMm5vjGqHPthJCMqKpqssSISRo' .
+            's0PYDTcEQzyyurfX67EJWKtZj6HNwuDMEGJ02iBNZfjUl7r8dIi28bSKhNlsfycXZKY' .
+            'RcIjp0+r5RqtR2auo9GQ6veKb61DEAGIqaR+uLLcJVTHCu0w9oXLGbRlGth5eNoj03C' .
+            'xXVAH2IfhbNwIDAQABo4IChzCCAoMwDAYDVR0TAQH/BAIwADCCAUgGA1UdIAEB/wSCA' .
+            'TwwggE4MIIBNAYJKoRoAYb3IwEBMIIBJTCB3QYIKwYBBQUHAgIwgdAMgc1EZWtsYXJh' .
+            'Y2phIHRhIGplc3Qgb8Wbd2lhZGN6ZW5pZW0gd3lkYXdjeSwgxbxlIHRlbiBjZXJ0eWZ' .
+            'pa2F0IHpvc3RhxYIgd3lkYW55IGpha28gY2VydHlmaWthdCBrd2FsaWZpa293YW55IH' .
+            'pnb2RuaWUgeiB3eW1hZ2FuaWFtaSB1c3Rhd3kgbyBwb2RwaXNpZSBlbGVrdHJvbmlje' .
+            'm55bSBvcmF6IHRvd2FyenlzesSFY3ltaSBqZWogcm96cG9yesSFZHplbmlhbWkuMEMG' .
+            'CCsGAQUFBwIBFjdodHRwOi8vd3d3Lmtpci5jb20ucGwvY2VydHlmaWthY2phX2tsdWN' .
+            '6eS9wb2xpdHlrYS5odG1sMAkGA1UdCQQCMAAwIQYDVR0RBBowGIEWai5wcnpld29yc2' .
+            'tpQGdkeW5pYS5wbDAOBgNVHQ8BAf8EBAMCBkAwgZ4GA1UdIwSBljCBk4AU3TGldJXip' .
+            'N4oGS3ZYmnBDMFs8gKhd6R1MHMxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dh' .
+            'IEl6YmEgUm96bGljemVuaW93YSBTLkEuMSQwIgYDVQQDDBtDT1BFIFNaQUZJUiAtIEt' .
+            '3YWxpZmlrb3dhbnkxFDASBgNVBAUTC05yIHdwaXN1OiA2ggJb9jBIBgNVHR8EQTA/MD' .
+            '2gO6A5hjdodHRwOi8vd3d3Lmtpci5jb20ucGwvY2VydHlmaWthY2phX2tsdWN6eS9DU' .
+            'kxfT1pLMzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQBYPIqnAreyeql7/opJjcar/qWZ' .
+            'y9ruhB2q0lZFsJOhwgMnbQXzp/4vv93YJqcHGAXdHP6EO8FQX47mjo2ZKQmi+cIHJHL' .
+            'ONdX/3Im+M17V0iNAh7Z1lOSfTRT+iiwe/F8phcEaD5q2RmvYusR7zXZq/cLL0If0hX' .
+            'oPZ/EHQxjN8pxzxiUx6bJAgturnIMEfRNesxwghdr1dkUjOhGLf3kHVzgM6j3VAM7oF' .
+            'mMUb5y5s96Bzl10DodWitjOEH0vvnIcsppSxH1C1dCAi0o9f/1y2XuLNhBNHMAyTqpY' .
+            'PX8Yvav1c+Z50OMaSXHAnTa20zv8UtiHbaAhwlifCelUMj93S';
+        
+        try {
+            Base64::decode($str, true);
+            $this->fail('Strict padding not enforced');
+        } catch (\Exception $ex) {
+
+            $this->assertSame(
+                Base64::decode($str),
+                \base64_decode($str)
+            );
+        }
+    }
+}

+ 58 - 0
api/vendor/paragonie/constant_time_encoding/tests/Base64UrlSafeTest.php

@@ -0,0 +1,58 @@
+<?php
+
+use ParagonIE\ConstantTime\Base64UrlSafe;
+use ParagonIE\ConstantTime\Binary;
+
+/**
+ * Class Base64UrlSafeTest
+ */
+class Base64UrlSafeTest extends PHPUnit\Framework\TestCase
+{
+    /**
+     * @covers Base64UrlSafe::encode()
+     * @covers Base64UrlSafe::decode()
+     *
+     * @throws Exception
+     * @throws TypeError
+     */
+    public function testRandom()
+    {
+        for ($i = 1; $i < 32; ++$i) {
+            for ($j = 0; $j < 50; ++$j) {
+                $random = \random_bytes($i);
+
+                $enc = Base64UrlSafe::encode($random);
+                $this->assertSame(
+                    $random,
+                    Base64UrlSafe::decode($enc)
+                );
+                $this->assertSame(
+                    \strtr(\base64_encode($random), '+/', '-_'),
+                    $enc
+                );
+
+                $unpadded = \rtrim($enc, '=');
+                $this->assertSame(
+                    $unpadded,
+                    Base64UrlSafe::encodeUnpadded($random)
+                );
+                $this->assertSame(
+                    $random,
+                    Base64UrlSafe::decode($unpadded)
+                );
+            }
+        }
+
+        $random = \random_bytes(1 << 20);
+        $enc = Base64UrlSafe::encode($random);
+        $this->assertTrue(Binary::safeStrlen($enc) > 65536);
+        $this->assertSame(
+            $random,
+            Base64UrlSafe::decode($enc)
+        );
+        $this->assertSame(
+            \strtr(\base64_encode($random), '+/', '-_'),
+            $enc
+        );
+    }
+}

+ 307 - 0
api/vendor/paragonie/constant_time_encoding/tests/EncodingTest.php

@@ -0,0 +1,307 @@
+<?php
+use \ParagonIE\ConstantTime\Base32;
+use \ParagonIE\ConstantTime\Base32Hex;
+use \ParagonIE\ConstantTime\Base64;
+use \ParagonIE\ConstantTime\Base64DotSlash;
+use \ParagonIE\ConstantTime\Base64DotSlashOrdered;
+use \ParagonIE\ConstantTime\Base64UrlSafe;
+use \ParagonIE\ConstantTime\Encoding;
+use \ParagonIE\ConstantTime\Hex;
+
+class EncodingTest extends PHPUnit\Framework\TestCase
+{
+    public function testBase32Encode()
+    {
+        $this->assertSame(
+            Encoding::base32Encode("\x00"),
+            'aa======'
+        );
+        $this->assertSame(
+            Encoding::base32Encode("\x00\x00"),
+            'aaaa===='
+        );
+        $this->assertSame(
+            Encoding::base32Encode("\x00\x00\x00"),
+            'aaaaa==='
+        );
+        $this->assertSame(
+            Encoding::base32Encode("\x00\x00\x00\x00"),
+            'aaaaaaa='
+        );
+        $this->assertSame(
+            Encoding::base32Encode("\x00\x00\x00\x00\x00"),
+            'aaaaaaaa'
+        );
+        $this->assertSame(
+            Encoding::base32Encode("\x00\x00\x0F\xFF\xFF"),
+            'aaaa7777'
+        );
+        $this->assertSame(
+            Encoding::base32Encode("\xFF\xFF\xF0\x00\x00"),
+            '7777aaaa'
+        );
+
+        $this->assertSame(
+            Encoding::base32Encode("\xce\x73\x9c\xe7\x39"),
+            'zzzzzzzz'
+        );
+        $this->assertSame(
+            Encoding::base32Encode("\xd6\xb5\xad\x6b\x5a"),
+            '22222222'
+        );
+        $this->assertSame(
+            Base32::encodeUpper("\x00"),
+            'AA======'
+        );
+        $this->assertSame(
+            Base32::encodeUpper("\x00\x00"),
+            'AAAA===='
+        );
+        $this->assertSame(
+            Base32::encodeUpper("\x00\x00\x00"),
+            'AAAAA==='
+        );
+        $this->assertSame(
+            Base32::encodeUpper("\x00\x00\x00\x00"),
+            'AAAAAAA='
+        );
+        $this->assertSame(
+            Base32::encodeUpper("\x00\x00\x00\x00\x00"),
+            'AAAAAAAA'
+        );
+        $this->assertSame(
+            Base32::encodeUpper("\x00\x00\x0F\xFF\xFF"),
+            'AAAA7777'
+        );
+        $this->assertSame(
+            Base32::encodeUpper("\xFF\xFF\xF0\x00\x00"),
+            '7777AAAA'
+        );
+
+        $this->assertSame(
+            Base32::encodeUpper("\xce\x73\x9c\xe7\x39"),
+            'ZZZZZZZZ'
+        );
+        $this->assertSame(
+            Base32::encodeUpper("\xd6\xb5\xad\x6b\x5a"),
+            '22222222'
+        );
+    }
+
+    public function testBase32Hex()
+    {
+        $this->assertSame(
+            Base32Hex::encode("\x00"),
+            '00======'
+        );
+        $this->assertSame(
+            Base32Hex::encode("\x00\x00"),
+            '0000===='
+        );
+        $this->assertSame(
+            Base32Hex::encode("\x00\x00\x00"),
+            '00000==='
+        );
+        $this->assertSame(
+            Base32Hex::encode("\x00\x00\x00\x00"),
+            '0000000='
+        );
+        $this->assertSame(
+            Base32Hex::encode("\x00\x00\x00\x00\x00"),
+            '00000000'
+        );
+        $this->assertSame(
+            Base32Hex::encode("\x00\x00\x0F\xFF\xFF"),
+            '0000vvvv'
+        );
+        $this->assertSame(
+            Base32Hex::encode("\xFF\xFF\xF0\x00\x00"),
+            'vvvv0000'
+        );
+
+
+    }
+
+    /**
+     * Based on test vectors from RFC 4648
+     */
+    public function testBase32Decode()
+    {
+        $this->assertSame(
+            "\x00\x00\x00\x00\x00\x00",
+            Encoding::base32Decode('aaaaaaaaaa======')
+        );
+        $this->assertSame(
+            "\x00\x00\x00\x00\x00\x00\x00",
+            Encoding::base32Decode('aaaaaaaaaaaa====')
+        );
+        $this->assertSame(
+            "\x00\x00\x00\x00\x00\x00\x00\x00",
+            Encoding::base32Decode('aaaaaaaaaaaaa===')
+        );
+        $this->assertSame(
+            "\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+            Encoding::base32Decode('aaaaaaaaaaaaaaa=')
+        );
+        $this->assertSame(
+            "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+            Encoding::base32Decode('aaaaaaaaaaaaaaaa')
+        );
+        $this->assertSame(
+            "\x00",
+            Encoding::base32Decode('aa======')
+        );
+        $this->assertSame(
+            "\x00\x00",
+            Encoding::base32Decode('aaaa====')
+        );
+        $this->assertSame(
+            "\x00\x00\x00",
+            Encoding::base32Decode('aaaaa===')
+        );
+        $this->assertSame(
+            "\x00\x00\x00\x00",
+            Encoding::base32Decode('aaaaaaa=')
+        );
+        $this->assertSame(
+            "\x00\x00\x00\x00\x00",
+            Encoding::base32Decode('aaaaaaaa')
+        );
+        $this->assertSame(
+            "\x00\x00\x0F\xFF\xFF",
+            Encoding::base32Decode('aaaa7777')
+        );
+        $this->assertSame(
+            "\xFF\xFF\xF0\x00\x00",
+            Encoding::base32Decode('7777aaaa')
+        );
+        $this->assertSame(
+            "\xce\x73\x9c\xe7\x39",
+            Encoding::base32Decode('zzzzzzzz')
+        );
+        $this->assertSame(
+            "\xd6\xb5\xad\x6b\x5a",
+            Encoding::base32Decode('22222222')
+        );
+        $this->assertSame(
+            'foobar',
+            Encoding::base32Decode('mzxw6ytboi======')
+        );
+
+        $rand = random_bytes(9);
+        $enc = Encoding::base32Encode($rand);
+
+        $this->assertSame(
+            Encoding::base32Encode($rand),
+            Encoding::base32Encode(Encoding::base32Decode($enc))
+        );
+        $this->assertSame(
+            $rand,
+            Encoding::base32Decode($enc)
+        );
+    }
+
+    /**
+     * @covers Encoding::hexDecode()
+     * @covers Encoding::hexEncode()
+     * @covers Encoding::base32Decode()
+     * @covers Encoding::base32Encode()
+     * @covers Encoding::base64Decode()
+     * @covers Encoding::base64Encode()
+     * @covers Encoding::base64DotSlashDecode()
+     * @covers Encoding::base64DotSlashEncode()
+     * @covers Encoding::base64DotSlashOrderedDecode()
+     * @covers Encoding::base64DotSlashOrderedEncode()
+     */
+    public function testBasicEncoding()
+    {
+        // Re-run the test at least 3 times for each length
+        for ($j = 0; $j < 3; ++$j) {
+            for ($i = 1; $i < 84; ++$i) {
+                $rand = random_bytes($i);
+                $enc = Encoding::hexEncode($rand);
+                $this->assertSame(
+                    \bin2hex($rand),
+                    $enc,
+                    "Hex Encoding - Length: " . $i
+                );
+                $this->assertSame(
+                    $rand,
+                    Encoding::hexDecode($enc),
+                    "Hex Encoding - Length: " . $i
+                );
+
+                // Uppercase variant:
+                $enc = Hex::encodeUpper($rand);
+                $this->assertSame(
+                    \strtoupper(\bin2hex($rand)),
+                    $enc,
+                    "Hex Encoding - Length: " . $i
+                );
+                $this->assertSame(
+                    $rand,
+                    Hex::decode($enc),
+                    "HexUpper Encoding - Length: " . $i
+                );
+
+                $enc = Encoding::base32Encode($rand);
+                $this->assertSame(
+                    $rand,
+                    Encoding::base32Decode($enc),
+                    "Base32 Encoding - Length: " . $i
+                );
+
+                $enc = Encoding::base32EncodeUpper($rand);
+                $this->assertSame(
+                    $rand,
+                    Encoding::base32DecodeUpper($enc),
+                    "Base32Upper Encoding - Length: " . $i
+                );
+
+                $enc = Encoding::base32HexEncode($rand);
+                $this->assertSame(
+                    bin2hex($rand),
+                    bin2hex(Encoding::base32HexDecode($enc)),
+                    "Base32Hex Encoding - Length: " . $i
+                );
+
+                $enc = Encoding::base32HexEncodeUpper($rand);
+                $this->assertSame(
+                    bin2hex($rand),
+                    bin2hex(Encoding::base32HexDecodeUpper($enc)),
+                    "Base32HexUpper Encoding - Length: " . $i
+                );
+
+                $enc = Encoding::base64Encode($rand);
+                $this->assertSame(
+                    $rand,
+                    Encoding::base64Decode($enc),
+                    "Base64 Encoding - Length: " . $i
+                );
+
+                $enc = Encoding::base64EncodeDotSlash($rand);
+                $this->assertSame(
+                    $rand,
+                    Encoding::base64DecodeDotSlash($enc),
+                    "Base64 DotSlash Encoding - Length: " . $i
+                );
+                $enc = Encoding::base64EncodeDotSlashOrdered($rand);
+                $this->assertSame(
+                    $rand,
+                    Encoding::base64DecodeDotSlashOrdered($enc),
+                    "Base64 Ordered DotSlash Encoding - Length: " . $i
+                );
+
+                $enc = Base64UrlSafe::encode($rand);
+                $this->assertSame(
+                    \strtr(\base64_encode($rand), '+/', '-_'),
+                    $enc
+                );
+                $this->assertSame(
+                    $rand,
+                    Base64UrlSafe::decode($enc)
+                );
+            }
+        }
+    }
+}

+ 39 - 0
api/vendor/paragonie/constant_time_encoding/tests/HexTest.php

@@ -0,0 +1,39 @@
+<?php
+use \ParagonIE\ConstantTime\Hex;
+
+class HexTest extends PHPUnit\Framework\TestCase
+{
+    /**
+     * @covers Hex::encode()
+     * @covers Hex::decode()
+     * @covers Hex::encodeUpper()
+     */
+    public function testRandom()
+    {
+        for ($i = 1; $i < 32; ++$i) {
+            for ($j = 0; $j < 50; ++$j) {
+                $random = \random_bytes($i);
+
+                $enc = Hex::encode($random);
+                $this->assertSame(
+                    $random,
+                    Hex::decode($enc)
+                );
+                $this->assertSame(
+                    \bin2hex($random),
+                    $enc
+                );
+
+                $enc = Hex::encodeUpper($random);
+                $this->assertSame(
+                    $random,
+                    Hex::decode($enc)
+                );
+                $this->assertSame(
+                    \strtoupper(\bin2hex($random)),
+                    $enc
+                );
+            }
+        }
+    }
+}

+ 84 - 0
api/vendor/paragonie/constant_time_encoding/tests/RFC4648Test.php

@@ -0,0 +1,84 @@
+<?php
+use \ParagonIE\ConstantTime\Base32;
+use \ParagonIE\ConstantTime\Base32Hex;
+use \ParagonIE\ConstantTime\Base64;
+use \ParagonIE\ConstantTime\Base64DotSlash;
+use \ParagonIE\ConstantTime\Base64DotSlashOrdered;
+use \ParagonIE\ConstantTime\Encoding;
+use \ParagonIE\ConstantTime\Hex;
+
+/**
+ * Class RFC4648Test
+ *
+ * @ref https://tools.ietf.org/html/rfc4648#section-10
+ */
+class RFC4648Test extends PHPUnit\Framework\TestCase
+{
+    public function testVectorBase64()
+    {
+        $this->assertSame(Base64::encode(''), '');
+        $this->assertSame(Base64::encode('f'), 'Zg==');
+        $this->assertSame(Base64::encode('fo'), 'Zm8=');
+        $this->assertSame(Base64::encode('foo'), 'Zm9v');
+        $this->assertSame(Base64::encode('foob'), 'Zm9vYg==');
+        $this->assertSame(Base64::encode('fooba'), 'Zm9vYmE=');
+        $this->assertSame(Base64::encode('foobar'), 'Zm9vYmFy');
+    }
+
+    public function testVectorBase32()
+    {
+        $this->assertSame(Base32::encode(''), '');
+        $this->assertSame(Base32::encode('f'), 'my======');
+        $this->assertSame(Base32::encode('fo'), 'mzxq====');
+        $this->assertSame(Base32::encode('foo'), 'mzxw6===');
+        $this->assertSame(Base32::encode('foob'), 'mzxw6yq=');
+        $this->assertSame(Base32::encode('fooba'), 'mzxw6ytb');
+        $this->assertSame(Base32::encode('foobar'), 'mzxw6ytboi======');
+
+        $this->assertSame(Base32::encodeUpper(''), '');
+        $this->assertSame(Base32::encodeUpper('f'), 'MY======');
+        $this->assertSame(Base32::encodeUpper('fo'), 'MZXQ====');
+        $this->assertSame(Base32::encodeUpper('foo'), 'MZXW6===');
+        $this->assertSame(Base32::encodeUpper('foob'), 'MZXW6YQ=');
+        $this->assertSame(Base32::encodeUpper('fooba'), 'MZXW6YTB');
+        $this->assertSame(Base32::encodeUpper('foobar'), 'MZXW6YTBOI======');
+    }
+
+    public function testVectorBase32Hex()
+    {
+        $this->assertSame(Base32Hex::encode(''), '');
+        $this->assertSame(Base32Hex::encode('f'), 'co======');
+        $this->assertSame(Base32Hex::encode('fo'), 'cpng====');
+        $this->assertSame(Base32Hex::encode('foo'), 'cpnmu===');
+        $this->assertSame(Base32Hex::encode('foob'), 'cpnmuog=');
+        $this->assertSame(Base32Hex::encode('fooba'), 'cpnmuoj1');
+        $this->assertSame(Base32Hex::encode('foobar'), 'cpnmuoj1e8======');
+
+        $this->assertSame(Base32Hex::encodeUpper(''), '');
+        $this->assertSame(Base32Hex::encodeUpper('f'), 'CO======');
+        $this->assertSame(Base32Hex::encodeUpper('fo'), 'CPNG====');
+        $this->assertSame(Base32Hex::encodeUpper('foo'), 'CPNMU===');
+        $this->assertSame(Base32Hex::encodeUpper('foob'), 'CPNMUOG=');
+        $this->assertSame(Base32Hex::encodeUpper('fooba'), 'CPNMUOJ1');
+        $this->assertSame(Base32Hex::encodeUpper('foobar'), 'CPNMUOJ1E8======');
+    }
+
+    public function testVectorBase16()
+    {
+        $this->assertSame(Hex::encode(''), '');
+        $this->assertSame(Hex::encode('f'), '66');
+        $this->assertSame(Hex::encode('fo'), '666f');
+        $this->assertSame(Hex::encode('foo'), '666f6f');
+        $this->assertSame(Hex::encode('foob'), '666f6f62');
+        $this->assertSame(Hex::encode('fooba'), '666f6f6261');
+        $this->assertSame(Hex::encode('foobar'), '666f6f626172');
+
+        $this->assertSame(Hex::encodeUpper(''), '');
+        $this->assertSame(Hex::encodeUpper('f'), '66');
+        $this->assertSame(Hex::encodeUpper('fo'), '666F');
+        $this->assertSame(Hex::encodeUpper('foo'), '666F6F');
+        $this->assertSame(Hex::encodeUpper('foob'), '666F6F62');
+        $this->assertSame(Hex::encodeUpper('fooba'), '666F6F6261');
+        $this->assertSame(Hex::encodeUpper('foobar'), '666F6F626172');
+    }
+}

+ 3 - 0
api/vendor/pragmarx/google2fa/.gitignore

@@ -0,0 +1,3 @@
+composer.phar
+vendor
+coverage

+ 40 - 0
api/vendor/pragmarx/google2fa/.scrutinizer.yml

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

+ 33 - 0
api/vendor/pragmarx/google2fa/.travis.yml

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

+ 7 - 0
api/vendor/pragmarx/google2fa/LICENSE.md

@@ -0,0 +1,7 @@
+Copyright 2014-2018 Phil, Antonio Carlos Ribeiro and All Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 276 - 0
api/vendor/pragmarx/google2fa/README.md

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

+ 29 - 0
api/vendor/pragmarx/google2fa/RELICENSED.md

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

+ 69 - 0
api/vendor/pragmarx/google2fa/changelog.md

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

+ 40 - 0
api/vendor/pragmarx/google2fa/composer.json

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

+ 1742 - 0
api/vendor/pragmarx/google2fa/composer.lock

@@ -0,0 +1,1742 @@
+{
+    "_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": "f0f90c5128c6c9067f83afae918475f4",
+    "packages": [
+        {
+            "name": "paragonie/constant_time_encoding",
+            "version": "v2.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/constant_time_encoding.git",
+                "reference": "7c74c5d08761ead7b5e89d07c854bc28eb0b2186"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/7c74c5d08761ead7b5e89d07c854bc28eb0b2186",
+                "reference": "7c74c5d08761ead7b5e89d07c854bc28eb0b2186",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6",
+                "vimeo/psalm": "^0.3|^1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "ParagonIE\\ConstantTime\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com",
+                    "role": "Maintainer"
+                },
+                {
+                    "name": "Steve 'Sc00bz' Thomas",
+                    "email": "steve@tobtu.com",
+                    "homepage": "https://www.tobtu.com",
+                    "role": "Original Developer"
+                }
+            ],
+            "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
+            "keywords": [
+                "base16",
+                "base32",
+                "base32_decode",
+                "base32_encode",
+                "base64",
+                "base64_decode",
+                "base64_encode",
+                "bin2hex",
+                "encoding",
+                "hex",
+                "hex2bin",
+                "rfc4648"
+            ],
+            "time": "2018-01-23T00:54:57+00:00"
+        },
+        {
+            "name": "paragonie/random_compat",
+            "version": "v2.0.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/random_compat.git",
+                "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8",
+                "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*|5.*"
+            },
+            "suggest": {
+                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/random.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com"
+                }
+            ],
+            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+            "keywords": [
+                "csprng",
+                "pseudorandom",
+                "random"
+            ],
+            "time": "2017-09-27T21:40:39+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php56",
+            "version": "v1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php56.git",
+                "reference": "ebc999ce5f14204c5150b9bd15f8f04e621409d8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/ebc999ce5f14204c5150b9bd15f8f04e621409d8",
+                "reference": "ebc999ce5f14204c5150b9bd15f8f04e621409d8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "symfony/polyfill-util": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php56\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-01-30T19:27:44+00:00"
+        },
+        {
+            "name": "symfony/polyfill-util",
+            "version": "v1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-util.git",
+                "reference": "e17c808ec4228026d4f5a8832afa19be85979563"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/e17c808ec4228026d4f5a8832afa19be85979563",
+                "reference": "e17c808ec4228026d4f5a8832afa19be85979563",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Util\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony utilities for portability of PHP codes",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compat",
+                "compatibility",
+                "polyfill",
+                "shim"
+            ],
+            "time": "2018-01-31T18:08:44+00:00"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "bacon/bacon-qr-code",
+            "version": "1.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Bacon/BaconQrCode.git",
+                "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/5a91b62b9d37cee635bbf8d553f4546057250bee",
+                "reference": "5a91b62b9d37cee635bbf8d553f4546057250bee",
+                "shasum": ""
+            },
+            "require": {
+                "ext-iconv": "*",
+                "php": "^5.4|^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8"
+            },
+            "suggest": {
+                "ext-gd": "to generate QR code images"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "BaconQrCode": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-2-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Ben Scholzen 'DASPRiD'",
+                    "email": "mail@dasprids.de",
+                    "homepage": "http://www.dasprids.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "BaconQrCode is a QR code generator for PHP.",
+            "homepage": "https://github.com/Bacon/BaconQrCode",
+            "time": "2017-10-17T09:59:25+00:00"
+        },
+        {
+            "name": "doctrine/instantiator",
+            "version": "1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/instantiator.git",
+                "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+                "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1"
+            },
+            "require-dev": {
+                "athletic/athletic": "~0.1.8",
+                "ext-pdo": "*",
+                "ext-phar": "*",
+                "phpunit/phpunit": "^6.2.3",
+                "squizlabs/php_codesniffer": "^3.0.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.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": "2017-07-22T11:58:36+00:00"
+        },
+        {
+            "name": "myclabs/deep-copy",
+            "version": "1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/DeepCopy.git",
+                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
+                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "doctrine/collections": "^1.0",
+                "doctrine/common": "^2.6",
+                "phpunit/phpunit": "^4.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "DeepCopy\\": "src/DeepCopy/"
+                },
+                "files": [
+                    "src/DeepCopy/deep_copy.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Create deep copies (clones) of your objects",
+            "keywords": [
+                "clone",
+                "copy",
+                "duplicate",
+                "object",
+                "object graph"
+            ],
+            "time": "2017-10-19T19:58:43+00:00"
+        },
+        {
+            "name": "phar-io/manifest",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phar-io/manifest.git",
+                "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0",
+                "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-phar": "*",
+                "phar-io/version": "^1.0.1",
+                "php": "^5.6 || ^7.0"
+            },
+            "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": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Heuer",
+                    "email": "sebastian@phpeople.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+            "time": "2017-03-05T18:14:27+00:00"
+        },
+        {
+            "name": "phar-io/version",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phar-io/version.git",
+                "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df",
+                "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Heuer",
+                    "email": "sebastian@phpeople.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Library for handling version information and constraints",
+            "time": "2017-03-05T17:38:23+00:00"
+        },
+        {
+            "name": "phpdocumentor/reflection-common",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+                "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
+                "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.6"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": [
+                        "src"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jaap van Otterdijk",
+                    "email": "opensource@ijaap.nl"
+                }
+            ],
+            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+            "homepage": "http://www.phpdoc.org",
+            "keywords": [
+                "FQSEN",
+                "phpDocumentor",
+                "phpdoc",
+                "reflection",
+                "static analysis"
+            ],
+            "time": "2017-09-11T18:02:19+00:00"
+        },
+        {
+            "name": "phpdocumentor/reflection-docblock",
+            "version": "4.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+                "reference": "94fd0001232e47129dd3504189fa1c7225010d08"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08",
+                "reference": "94fd0001232e47129dd3504189fa1c7225010d08",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0",
+                "phpdocumentor/reflection-common": "^1.0.0",
+                "phpdocumentor/type-resolver": "^0.4.0",
+                "webmozart/assert": "^1.0"
+            },
+            "require-dev": {
+                "doctrine/instantiator": "~1.0.5",
+                "mockery/mockery": "^1.0",
+                "phpunit/phpunit": "^6.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": [
+                        "src/"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mike van Riel",
+                    "email": "me@mikevanriel.com"
+                }
+            ],
+            "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+            "time": "2017-11-30T07:14:17+00:00"
+        },
+        {
+            "name": "phpdocumentor/type-resolver",
+            "version": "0.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/TypeResolver.git",
+                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
+                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5 || ^7.0",
+                "phpdocumentor/reflection-common": "^1.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "^0.9.4",
+                "phpunit/phpunit": "^5.2||^4.8.24"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": [
+                        "src/"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mike van Riel",
+                    "email": "me@mikevanriel.com"
+                }
+            ],
+            "time": "2017-07-14T14:27:02+00:00"
+        },
+        {
+            "name": "phpspec/prophecy",
+            "version": "1.7.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpspec/prophecy.git",
+                "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401",
+                "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/instantiator": "^1.0.2",
+                "php": "^5.3|^7.0",
+                "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
+                "sebastian/comparator": "^1.1|^2.0",
+                "sebastian/recursion-context": "^1.0|^2.0|^3.0"
+            },
+            "require-dev": {
+                "phpspec/phpspec": "^2.5|^3.2",
+                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.7.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": "2018-02-19T10:16:54+00:00"
+        },
+        {
+            "name": "phpunit/php-code-coverage",
+            "version": "5.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+                "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/661f34d0bd3f1a7225ef491a70a020ad23a057a1",
+                "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-xmlwriter": "*",
+                "php": "^7.0",
+                "phpunit/php-file-iterator": "^1.4.2",
+                "phpunit/php-text-template": "^1.2.1",
+                "phpunit/php-token-stream": "^2.0.1",
+                "sebastian/code-unit-reverse-lookup": "^1.0.1",
+                "sebastian/environment": "^3.0",
+                "sebastian/version": "^2.0.1",
+                "theseer/tokenizer": "^1.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.0"
+            },
+            "suggest": {
+                "ext-xdebug": "^2.5.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.3.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": "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": "2017-12-06T09:29:45+00:00"
+        },
+        {
+            "name": "phpunit/php-file-iterator",
+            "version": "1.4.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
+                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
+                "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": "2017-11-27T13:52:08+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.9",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-timer.git",
+                "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+                "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.3 || ^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+            },
+            "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": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Utility class for timing",
+            "homepage": "https://github.com/sebastianbergmann/php-timer/",
+            "keywords": [
+                "timer"
+            ],
+            "time": "2017-02-26T11:10:40+00:00"
+        },
+        {
+            "name": "phpunit/php-token-stream",
+            "version": "2.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+                "reference": "791198a2c6254db10131eecfe8c06670700904db"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
+                "reference": "791198a2c6254db10131eecfe8c06670700904db",
+                "shasum": ""
+            },
+            "require": {
+                "ext-tokenizer": "*",
+                "php": "^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.2.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-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": "2017-11-27T05:48:46+00:00"
+        },
+        {
+            "name": "phpunit/phpunit",
+            "version": "6.5.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/phpunit.git",
+                "reference": "6bd77b57707c236833d2b57b968e403df060c9d9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6bd77b57707c236833d2b57b968e403df060c9d9",
+                "reference": "6bd77b57707c236833d2b57b968e403df060c9d9",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-xml": "*",
+                "myclabs/deep-copy": "^1.6.1",
+                "phar-io/manifest": "^1.0.1",
+                "phar-io/version": "^1.0",
+                "php": "^7.0",
+                "phpspec/prophecy": "^1.7",
+                "phpunit/php-code-coverage": "^5.3",
+                "phpunit/php-file-iterator": "^1.4.3",
+                "phpunit/php-text-template": "^1.2.1",
+                "phpunit/php-timer": "^1.0.9",
+                "phpunit/phpunit-mock-objects": "^5.0.5",
+                "sebastian/comparator": "^2.1",
+                "sebastian/diff": "^2.0",
+                "sebastian/environment": "^3.1",
+                "sebastian/exporter": "^3.1",
+                "sebastian/global-state": "^2.0",
+                "sebastian/object-enumerator": "^3.0.3",
+                "sebastian/resource-operations": "^1.0",
+                "sebastian/version": "^2.0.1"
+            },
+            "conflict": {
+                "phpdocumentor/reflection-docblock": "3.0.2",
+                "phpunit/dbunit": "<3.0"
+            },
+            "require-dev": {
+                "ext-pdo": "*"
+            },
+            "suggest": {
+                "ext-xdebug": "*",
+                "phpunit/php-invoker": "^1.1"
+            },
+            "bin": [
+                "phpunit"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "6.5.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": "2018-02-26T07:01:09+00:00"
+        },
+        {
+            "name": "phpunit/phpunit-mock-objects",
+            "version": "5.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
+                "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf",
+                "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/instantiator": "^1.0.5",
+                "php": "^7.0",
+                "phpunit/php-text-template": "^1.2.1",
+                "sebastian/exporter": "^3.1"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<6.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.5"
+            },
+            "suggest": {
+                "ext-soap": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.0.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": "Mock Object library for PHPUnit",
+            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+            "keywords": [
+                "mock",
+                "xunit"
+            ],
+            "time": "2018-01-06T05:45:45+00:00"
+        },
+        {
+            "name": "sebastian/code-unit-reverse-lookup",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7 || ^6.0"
+            },
+            "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": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Looks up which function or method a line of code belongs to",
+            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+            "time": "2017-03-04T06:30:41+00:00"
+        },
+        {
+            "name": "sebastian/comparator",
+            "version": "2.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/comparator.git",
+                "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9",
+                "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0",
+                "sebastian/diff": "^2.0 || ^3.0",
+                "sebastian/exporter": "^3.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.1.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": "https://github.com/sebastianbergmann/comparator",
+            "keywords": [
+                "comparator",
+                "compare",
+                "equality"
+            ],
+            "time": "2018-02-01T13:46:46+00:00"
+        },
+        {
+            "name": "sebastian/diff",
+            "version": "2.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/diff.git",
+                "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
+                "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-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": "2017-08-03T08:09:46+00:00"
+        },
+        {
+            "name": "sebastian/environment",
+            "version": "3.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/environment.git",
+                "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
+                "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1.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": "2017-07-01T08:51:00+00:00"
+        },
+        {
+            "name": "sebastian/exporter",
+            "version": "3.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/exporter.git",
+                "reference": "234199f4528de6d12aaa58b612e98f7d36adb937"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937",
+                "reference": "234199f4528de6d12aaa58b612e98f7d36adb937",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0",
+                "sebastian/recursion-context": "^3.0"
+            },
+            "require-dev": {
+                "ext-mbstring": "*",
+                "phpunit/phpunit": "^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1.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": "2017-04-03T13:19:02+00:00"
+        },
+        {
+            "name": "sebastian/global-state",
+            "version": "2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/global-state.git",
+                "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+                "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.0"
+            },
+            "suggest": {
+                "ext-uopz": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.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": "2017-04-27T15:39:26+00:00"
+        },
+        {
+            "name": "sebastian/object-enumerator",
+            "version": "3.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+                "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+                "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0",
+                "sebastian/object-reflector": "^1.1.1",
+                "sebastian/recursion-context": "^3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+            "time": "2017-08-03T12:35:26+00:00"
+        },
+        {
+            "name": "sebastian/object-reflector",
+            "version": "1.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-reflector.git",
+                "reference": "773f97c67f28de00d397be301821b06708fca0be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
+                "reference": "773f97c67f28de00d397be301821b06708fca0be",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Allows reflection of object attributes, including inherited and non-public ones",
+            "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+            "time": "2017-03-29T09:07:27+00:00"
+        },
+        {
+            "name": "sebastian/recursion-context",
+            "version": "3.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/recursion-context.git",
+                "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+                "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.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": "2017-03-03T06:23:57+00:00"
+        },
+        {
+            "name": "sebastian/resource-operations",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/resource-operations.git",
+                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6.0"
+            },
+            "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": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides a list of PHP built-in functions that operate on resources",
+            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+            "time": "2015-07-28T20:34:47+00:00"
+        },
+        {
+            "name": "sebastian/version",
+            "version": "2.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/version.git",
+                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.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": "Library that helps with managing the version number of Git-hosted PHP projects",
+            "homepage": "https://github.com/sebastianbergmann/version",
+            "time": "2016-10-03T07:35:21+00:00"
+        },
+        {
+            "name": "theseer/tokenizer",
+            "version": "1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/theseer/tokenizer.git",
+                "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b",
+                "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-tokenizer": "*",
+                "ext-xmlwriter": "*",
+                "php": "^7.0"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+            "time": "2017-04-07T12:08:54+00:00"
+        },
+        {
+            "name": "webmozart/assert",
+            "version": "1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/webmozart/assert.git",
+                "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
+                "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.3 || ^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.6",
+                "sebastian/version": "^1.0.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Webmozart\\Assert\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@gmail.com"
+                }
+            ],
+            "description": "Assertions to validate method input/output with nice error messages.",
+            "keywords": [
+                "assert",
+                "check",
+                "validate"
+            ],
+            "time": "2018-01-29T19:49:41+00:00"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "dev",
+    "stability-flags": [],
+    "prefer-stable": true,
+    "prefer-lowest": false,
+    "platform": {
+        "php": ">=5.4"
+    },
+    "platform-dev": []
+}

BIN
api/vendor/pragmarx/google2fa/docs/playground.jpg


+ 34 - 0
api/vendor/pragmarx/google2fa/phpunit.xml

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

+ 10 - 0
api/vendor/pragmarx/google2fa/src/Exceptions/IncompatibleWithGoogleAuthenticatorException.php

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

+ 10 - 0
api/vendor/pragmarx/google2fa/src/Exceptions/InsecureCallException.php

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

+ 10 - 0
api/vendor/pragmarx/google2fa/src/Exceptions/InvalidCharactersException.php

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

+ 10 - 0
api/vendor/pragmarx/google2fa/src/Exceptions/SecretKeyTooShortException.php

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

+ 354 - 0
api/vendor/pragmarx/google2fa/src/Google2FA.php

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

+ 135 - 0
api/vendor/pragmarx/google2fa/src/Support/Base32.php

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

+ 21 - 0
api/vendor/pragmarx/google2fa/src/Support/Constants.php

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

+ 91 - 0
api/vendor/pragmarx/google2fa/src/Support/QRCode.php

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

+ 16 - 0
api/vendor/pragmarx/google2fa/src/Support/Url.php

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

+ 0 - 0
api/vendor/pragmarx/google2fa/tests/.gitkeep


Fichier diff supprimé car celui-ci est trop grand
+ 16 - 0
api/vendor/pragmarx/google2fa/tests/Constants.php


+ 224 - 0
api/vendor/pragmarx/google2fa/tests/Google2FATest.php

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

+ 42 - 0
api/vendor/pragmarx/google2fa/tests/bootstrap.php

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

+ 2 - 0
api/vendor/pragmarx/google2fa/upgrading.md

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

+ 19 - 0
api/vendor/symfony/polyfill-php56/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2015-2018 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 138 - 0
api/vendor/symfony/polyfill-php56/Php56.php

@@ -0,0 +1,138 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Php56;
+
+use Symfony\Polyfill\Util\Binary;
+
+/**
+ * @internal
+ */
+final class Php56
+{
+    const LDAP_ESCAPE_FILTER = 1;
+    const LDAP_ESCAPE_DN = 2;
+
+    public static function hash_equals($knownString, $userInput)
+    {
+        if (!\is_string($knownString)) {
+            trigger_error('Expected known_string to be a string, '.gettype($knownString).' given', E_USER_WARNING);
+
+            return false;
+        }
+
+        if (!\is_string($userInput)) {
+            trigger_error('Expected user_input to be a string, '.gettype($userInput).' given', E_USER_WARNING);
+
+            return false;
+        }
+
+        $knownLen = Binary::strlen($knownString);
+        $userLen = Binary::strlen($userInput);
+
+        if ($knownLen !== $userLen) {
+            return false;
+        }
+
+        $result = 0;
+
+        for ($i = 0; $i < $knownLen; ++$i) {
+            $result |= \ord($knownString[$i]) ^ \ord($userInput[$i]);
+        }
+
+        return 0 === $result;
+    }
+
+    /**
+     * Stub implementation of the {@link ldap_escape()} function of the ldap
+     * extension.
+     *
+     * Escape strings for safe use in LDAP filters and DNs.
+     *
+     * @author Chris Wright <ldapi@daverandom.com>
+     *
+     * @param string $subject
+     * @param string $ignore
+     * @param int    $flags
+     *
+     * @return string
+     *
+     * @see http://stackoverflow.com/a/8561604
+     */
+    public static function ldap_escape($subject, $ignore = '', $flags = 0)
+    {
+        static $charMaps = null;
+
+        if (null === $charMaps) {
+            $charMaps = array(
+                self::LDAP_ESCAPE_FILTER => array('\\', '*', '(', ')', "\x00"),
+                self::LDAP_ESCAPE_DN => array('\\', ',', '=', '+', '<', '>', ';', '"', '#', "\r"),
+            );
+
+            $charMaps[0] = array();
+
+            for ($i = 0; $i < 256; ++$i) {
+                $charMaps[0][\chr($i)] = sprintf('\\%02x', $i);
+            }
+
+            for ($i = 0, $l = \count($charMaps[self::LDAP_ESCAPE_FILTER]); $i < $l; ++$i) {
+                $chr = $charMaps[self::LDAP_ESCAPE_FILTER][$i];
+                unset($charMaps[self::LDAP_ESCAPE_FILTER][$i]);
+                $charMaps[self::LDAP_ESCAPE_FILTER][$chr] = $charMaps[0][$chr];
+            }
+
+            for ($i = 0, $l = \count($charMaps[self::LDAP_ESCAPE_DN]); $i < $l; ++$i) {
+                $chr = $charMaps[self::LDAP_ESCAPE_DN][$i];
+                unset($charMaps[self::LDAP_ESCAPE_DN][$i]);
+                $charMaps[self::LDAP_ESCAPE_DN][$chr] = $charMaps[0][$chr];
+            }
+        }
+
+        // Create the base char map to escape
+        $flags = (int) $flags;
+        $charMap = array();
+
+        if ($flags & self::LDAP_ESCAPE_FILTER) {
+            $charMap += $charMaps[self::LDAP_ESCAPE_FILTER];
+        }
+
+        if ($flags & self::LDAP_ESCAPE_DN) {
+            $charMap += $charMaps[self::LDAP_ESCAPE_DN];
+        }
+
+        if (!$charMap) {
+            $charMap = $charMaps[0];
+        }
+
+        // Remove any chars to ignore from the list
+        $ignore = (string) $ignore;
+
+        for ($i = 0, $l = \strlen($ignore); $i < $l; ++$i) {
+            unset($charMap[$ignore[$i]]);
+        }
+
+        // Do the main replacement
+        $result = strtr($subject, $charMap);
+
+        // Encode leading/trailing spaces if self::LDAP_ESCAPE_DN is passed
+        if ($flags & self::LDAP_ESCAPE_DN) {
+            if ($result[0] === ' ') {
+                $result = '\\20'.substr($result, 1);
+            }
+
+            if ($result[\strlen($result) - 1] === ' ') {
+                $result = substr($result, 0, -1).'\\20';
+            }
+        }
+
+        return $result;
+    }
+}

+ 15 - 0
api/vendor/symfony/polyfill-php56/README.md

@@ -0,0 +1,15 @@
+Symfony Polyfill / Php56
+========================
+
+This component provides functions unavailable in releases prior to PHP 5.6:
+
+- [`hash_equals`](http://php.net/hash_equals)  (part of [hash](http://php.net/hash) extension)
+- [`ldap_escape`](http://php.net/ldap_escape) (part of [ldap](http://php.net/ldap) extension)
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).

+ 38 - 0
api/vendor/symfony/polyfill-php56/bootstrap.php

@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Php56 as p;
+
+if (PHP_VERSION_ID < 50600) {
+    if (!function_exists('hash_equals')) {
+        function hash_equals($knownString, $userInput) { return p\Php56::hash_equals($knownString, $userInput); }
+    }
+    if (extension_loaded('ldap') && !function_exists('ldap_escape')) {
+        define('LDAP_ESCAPE_FILTER', 1);
+        define('LDAP_ESCAPE_DN', 2);
+
+        function ldap_escape($subject, $ignore = '', $flags = 0) { return p\Php56::ldap_escape($subject, $ignore, $flags); }
+    }
+
+    if (50509 === PHP_VERSION_ID && 4 === PHP_INT_SIZE) {
+        // Missing functions in PHP 5.5.9 - affects 32 bit builds of Ubuntu 14.04LTS
+        // See https://bugs.launchpad.net/ubuntu/+source/php5/+bug/1315888
+        if (!function_exists('gzopen') && function_exists('gzopen64')) {
+            function gzopen($filename, $mode, $use_include_path = 0) { return gzopen64($filename, $mode, $use_include_path); }
+        }
+        if (!function_exists('gzseek') && function_exists('gzseek64')) {
+            function gzseek($zp, $offset, $whence = SEEK_SET) { return gzseek64($zp, $offset, $whence); }
+        }
+        if (!function_exists('gztell') && function_exists('gztell64')) {
+            function gztell($zp) { return gztell64($zp); }
+        }
+    }
+}

+ 32 - 0
api/vendor/symfony/polyfill-php56/composer.json

@@ -0,0 +1,32 @@
+{
+    "name": "symfony/polyfill-php56",
+    "type": "library",
+    "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
+    "keywords": ["polyfill", "shim", "compatibility", "portable"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.3",
+        "symfony/polyfill-util": "~1.0"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Polyfill\\Php56\\": "" },
+        "files": [ "bootstrap.php" ]
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.9-dev"
+        }
+    }
+}

+ 18 - 0
api/vendor/symfony/polyfill-util/Binary.php

@@ -0,0 +1,18 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Util;
+
+if (extension_loaded('mbstring')) {
+    class Binary extends BinaryOnFuncOverload {}
+} else {
+    class Binary extends BinaryNoFuncOverload {}
+}

+ 65 - 0
api/vendor/symfony/polyfill-util/BinaryNoFuncOverload.php

@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Util;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+class BinaryNoFuncOverload
+{
+    public static function strlen($s)
+    {
+        return \strlen($s);
+    }
+
+    public static function strpos($haystack, $needle, $offset = 0)
+    {
+        return strpos($haystack, $needle, $offset);
+    }
+
+    public static function strrpos($haystack, $needle, $offset = 0)
+    {
+        return strrpos($haystack, $needle, $offset);
+    }
+
+    public static function substr($string, $start, $length = PHP_INT_MAX)
+    {
+        return substr($string, $start, $length);
+    }
+
+    public static function stripos($s, $needle, $offset = 0)
+    {
+        return stripos($s, $needle, $offset);
+    }
+
+    public static function stristr($s, $needle, $part = false)
+    {
+        return stristr($s, $needle, $part);
+    }
+
+    public static function strrchr($s, $needle, $part = false)
+    {
+        return strrchr($s, $needle, $part);
+    }
+
+    public static function strripos($s, $needle, $offset = 0)
+    {
+        return strripos($s, $needle, $offset);
+    }
+
+    public static function strstr($s, $needle, $part = false)
+    {
+        return strstr($s, $needle, $part);
+    }
+}

+ 67 - 0
api/vendor/symfony/polyfill-util/BinaryOnFuncOverload.php

@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Util;
+
+/**
+ * Binary safe version of string functions overloaded when MB_OVERLOAD_STRING is enabled.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+class BinaryOnFuncOverload
+{
+    public static function strlen($s)
+    {
+        return mb_strlen($s, '8bit');
+    }
+
+    public static function strpos($haystack, $needle, $offset = 0)
+    {
+        return mb_strpos($haystack, $needle, $offset, '8bit');
+    }
+
+    public static function strrpos($haystack, $needle, $offset = 0)
+    {
+        return mb_strrpos($haystack, $needle, $offset, '8bit');
+    }
+
+    public static function substr($string, $start, $length = 2147483647)
+    {
+        return mb_substr($string, $start, $length, '8bit');
+    }
+
+    public static function stripos($s, $needle, $offset = 0)
+    {
+        return mb_stripos($s, $needle, $offset, '8bit');
+    }
+
+    public static function stristr($s, $needle, $part = false)
+    {
+        return mb_stristr($s, $needle, $part, '8bit');
+    }
+
+    public static function strrchr($s, $needle, $part = false)
+    {
+        return mb_strrchr($s, $needle, $part, '8bit');
+    }
+
+    public static function strripos($s, $needle, $offset = 0)
+    {
+        return mb_strripos($s, $needle, $offset, '8bit');
+    }
+
+    public static function strstr($s, $needle, $part = false)
+    {
+        return mb_strstr($s, $needle, $part, '8bit');
+    }
+}

+ 19 - 0
api/vendor/symfony/polyfill-util/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2015-2018 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 84 - 0
api/vendor/symfony/polyfill-util/LegacyTestListener.php

@@ -0,0 +1,84 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Util;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class LegacyTestListener extends \PHPUnit_Framework_TestSuite implements \PHPUnit_Framework_TestListener
+{
+    private $suite;
+    private $trait;
+
+    public function __construct(\PHPUnit_Framework_TestSuite $suite = null)
+    {
+        if ($suite) {
+            $this->suite = $suite;
+            $this->setName($suite->getName().' with polyfills enabled');
+            $this->addTest($suite);
+        }
+        $this->trait = new TestListenerTrait();
+    }
+
+    public function startTestSuite(\PHPUnit_Framework_TestSuite $suite)
+    {
+        $this->trait->startTestSuite($suite);
+    }
+
+    protected function setUp()
+    {
+        TestListenerTrait::$enabledPolyfills = $this->suite->getName();
+    }
+
+    protected function tearDown()
+    {
+        TestListenerTrait::$enabledPolyfills = false;
+    }
+
+    public function addError(\PHPUnit_Framework_Test $test, \Exception $e, $time)
+    {
+        $this->trait->addError($test, $e, $time);
+    }
+
+    public function addWarning(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_Warning $e, $time)
+    {
+    }
+
+    public function addFailure(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_AssertionFailedError $e, $time)
+    {
+        $this->trait->addError($test, $e, $time);
+    }
+
+    public function addIncompleteTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
+    {
+    }
+
+    public function addRiskyTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
+    {
+    }
+
+    public function addSkippedTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
+    {
+    }
+
+    public function endTestSuite(\PHPUnit_Framework_TestSuite $suite)
+    {
+    }
+
+    public function startTest(\PHPUnit_Framework_Test $test)
+    {
+    }
+
+    public function endTest(\PHPUnit_Framework_Test $test, $time)
+    {
+    }
+}

+ 13 - 0
api/vendor/symfony/polyfill-util/README.md

@@ -0,0 +1,13 @@
+Symfony Polyfill / Util
+=======================
+
+This component provides binary-safe string functions, using the
+[mbstring](https://php.net/mbstring) extension when available.
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).

+ 30 - 0
api/vendor/symfony/polyfill-util/composer.json

@@ -0,0 +1,30 @@
+{
+    "name": "symfony/polyfill-util",
+    "type": "library",
+    "description": "Symfony utilities for portability of PHP codes",
+    "keywords": ["polyfill", "shim", "compat", "compatibility"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.3"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Polyfill\\Util\\": "" }
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.9-dev"
+        }
+    }
+}

+ 10 - 0
css/organizr.css

@@ -1147,4 +1147,14 @@ img.img-chooser {
 .chat-list,
 .chatonline {
     height: calc(100vh - 130px) !important;
+}
+.tfa-input{
+    font-size: 400%;
+    height: 100%;
+}
+.center {
+    display: block;
+    margin-left: auto;
+    margin-right: auto;
+    width: 50%;
 }

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
css/organizr.min.css


+ 6 - 2
js/custom.js

@@ -342,10 +342,14 @@ $(document).on("click", ".login-button", function(e) {
         var html = JSON.parse(data);
         if(html.data == true){
             location.reload();
-        }else if(html.data == 'mismatch'){
+        }else if(html.data == 'mismatch') {
             $('div.login-box').unblock({});
-            message('Login Error',' Wrong username/email/password combo',activeInfo.settings.notifications.position,'#FFF','warning','10000');
+            message('Login Error', ' Wrong username/email/password combo', activeInfo.settings.notifications.position, '#FFF', 'warning', '10000');
             console.error('Organizr Function: Login failed - wrong username/email/password');
+        }else if(html.data == '2FA'){
+            $('div.login-box').unblock({});
+            $('#tfa-div').removeClass('hidden');
+            $('#loginform [name=tfaCode]').focus()
         }else{
             $('div.login-box').unblock({});
             message('Login Error',html.data,activeInfo.settings.notifications.position,'#FFF','warning','10000');

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
js/custom.min.js


+ 151 - 0
js/functions.js

@@ -1567,6 +1567,126 @@ function updateUserInformation(){
 		ajaxloader();
 	}
 }
+function twoFA(action, type, secret = null){
+    switch(action){
+        case 'activate':
+            organizrAPI('POST','api/?v1/2fa/create',{type:type}).success(function(data) {
+                var html = JSON.parse(data);
+                $('.twofa-modal-title').html(html.data.type);
+                $('.twofa-modal-image').html('<img class="center" src="'+html.data.url+'">');
+                $('.twofa-modal-secret').html(html.data.secret);
+                $('#twofa-modal').modal('show');
+            }).fail(function(xhr) {
+                console.error("Organizr Function: Connection Failed");
+            });
+            break;
+        case 'deactivate':
+            organizrAPI('GET','api/?v1/2fa/remove').success(function(data) {
+                var html = JSON.parse(data);
+                $('.2fa-list').replaceWith(buildTwoFA('internal'));
+            }).fail(function(xhr) {
+                console.error("Organizr Function: Connection Failed");
+            });
+            break;
+        case 'verify':
+            var secret = $('.twofa-modal-secret').text();
+            var code = $('#twofa-verify').val();
+            if(type !== '' && secret !== '' && code !== ''){
+                organizrAPI('POST','api/?v1/2fa/verify',{type:type, secret:secret, code:code}).success(function(data) {
+                    var html = JSON.parse(data);
+                    if(html.data == true){
+                        message('2FA Success','Input Code Validated! Saving...',activeInfo.settings.notifications.position,"#FFF","success","5000");
+                        $('#twofa-modal').modal('hide');
+                        twoFA('save', type, secret);
+                    }else{
+                        message('2FA Failed','Code Incorrect',activeInfo.settings.notifications.position,"#FFF","warning","5000");
+                    }
+                }).fail(function(xhr) {
+                    console.error("Organizr Function: Connection Failed");
+                });
+            }else{
+                message('2FA Failed','Input Code',activeInfo.settings.notifications.position,"#FFF","warning","5000");
+            }
+            break;
+        case 'save':
+            organizrAPI('POST','api/?v1/2fa/save',{type:type, secret:secret}).success(function(data) {
+                var html = JSON.parse(data);
+                console.log(html);
+                if(html.data == true){
+                    message('2FA Success','2FA Saved',activeInfo.settings.notifications.position,"#FFF","success","5000");
+                    $('.2fa-list').replaceWith(buildTwoFA(type));
+                }else{
+                    message('2FA Failed','2FA Error!',activeInfo.settings.notifications.position,"#FFF","warning","5000");
+                }
+            }).fail(function(xhr) {
+                console.error("Organizr Function: Connection Failed");
+            });
+            break;
+    }
+}
+function buildTwoFA(current){
+    switch(current){
+        case 'internal':
+            var option = `
+                <div class="col-lg-3 col-sm-6 row-in-br">
+                    <ul class="col-in">
+                        <li>
+                            <span class="circle circle-md bg-info"><i class="mdi mdi-webpack mdi-24px"></i></span>
+                        </li>
+                        <li class="col-middle">
+                            <h5>Organizr Authenticator</h5>
+                            <h5><span lang="en">Current</span></h5>
+                        </li>
+                    </ul>
+                </div>
+                <div class="col-lg-3 col-sm-6 row-in-br">
+                    <ul class="col-in">
+                        <li>
+                            <span class="circle circle-md bg-info"><i class="fa fa-google"></i></span>
+                        </li>
+                        <li class="col-middle">
+                            <h5>Google Authenticator</h5>
+                            <h5><a href="javascript:void(0)" onclick="twoFA('activate','google');"><span lang="en">Activate</span></a></h5>
+                        </li>
+                    </ul>
+                </div>
+            `;
+            break;
+        case 'google':
+            var option = `
+                <div class="col-lg-3 col-sm-6 row-in-br">
+                    <ul class="col-in">
+                        <li>
+                            <span class="circle circle-md bg-info"><i class="fa fa-google"></i></span>
+                        </li>
+                        <li class="col-middle">
+                            <h5>Google Authenticator</h5>
+                            <h5><a href="javascript:void(0)" onclick="twoFA('deactivate','google');"><span lang="en">Deactivate</span></a></h5>
+                        </li>
+                    </ul>
+                </div>
+            `;
+            break;
+        default:
+            break;
+    }
+    var element = `
+    <div class="white-box 2fa-list">
+        <div class="row row-in">
+            `+option+`
+        </div>
+    </div>
+    `;
+
+
+
+
+
+
+
+
+    return element;
+}
 function accountManager(user){
     var passwordMessage = '';
     switch(activeInfo.settings.misc.authBackend){
@@ -1610,6 +1730,36 @@ function accountManager(user){
     }
 	if (user.data.user.loggedin === true) {
 		var accountDiv = `
+        <!-- 2fa modal content -->
+        <div id="twofa-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="twofa-modal-label" aria-hidden="true">
+            <div class="modal-dialog">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+                        <h4 class="modal-title" id="twofa-modal-label">Enable 2FA</h4> </div>
+                    <div class="modal-body">
+                        <h4 class="twofa-modal-title text-center text-uppercase"></h4>
+                        <p class="twofa-modal-image"></p>
+                        <h5 class="twofa-modal-secret text-center"></h5>
+                        <div class="form-group m-t-10">
+                            <div class="input-group" style="width: 100%;">
+                                <div class="input-group-addon hidden-xs"><i class="ti-lock"></i></div>
+                                <input type="text" class="form-control tfa-input" id="twofa-verify" placeholder="Code" autocomplete="off" autocorrect="off" autocapitalize="off" maxlength="6" spellcheck="false" autofocus="" required="">
+                            </div>
+                            <br>
+                            <button class="btn btn-block btn-info" onclick="twoFA('verify','google');">Verify</button>
+
+                        </div>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-info waves-effect" data-dismiss="modal">Cancel</button>
+                    </div>
+                </div>
+                <!-- /.modal-content -->
+            </div>
+            <!-- /.modal-dialog -->
+        </div>
+        <!-- /.modal -->
 		<div id="account-area" class="white-popup mfp-with-anim mfp-hide">
 			<div class="col-md-10 col-md-offset-1">
 				<div class="row">
@@ -1626,6 +1776,7 @@ function accountManager(user){
 							<div class="panel-wrapper collapse in main-email-panel" aria-expanded="true">
 								<div class="panel-body">
 									<div class="form-body">
+									    `+buildTwoFA(user.data.user.authService)+`
 										<div class="row">
 											<div class="col-md-6">
 												<div class="form-group">

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff