diff --git a/lam/composer.json b/lam/composer.json index 7eadeac4..68a77fea 100644 --- a/lam/composer.json +++ b/lam/composer.json @@ -4,6 +4,7 @@ }, "require" : { "web-auth/webauthn-lib" : "2.1.7", - "symfony/http-foundation" : "5.0.0" + "symfony/http-foundation" : "5.0.0", + "symfony/psr-http-message-bridge" : "1.3.0" } } \ No newline at end of file diff --git a/lam/composer.lock b/lam/composer.lock index b60ea17c..93f7d6d8 100644 --- a/lam/composer.lock +++ b/lam/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ba2488b4997bb9328901b5be3ed4bed0", + "content-hash": "ef5f7241f5ed768a1c63843aadbb54aa", "packages": [ { "name": "beberlei/assert", @@ -764,7 +764,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.13.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -822,7 +822,7 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.13.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -884,7 +884,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.13.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -943,7 +943,7 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.13.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", @@ -996,6 +996,71 @@ ], "time": "2019-11-27T13:56:44+00:00" }, + { + "name": "symfony/psr-http-message-bridge", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/psr-http-message-bridge.git", + "reference": "9d3e80d54d9ae747ad573cad796e8e247df7b796" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/9d3e80d54d9ae747ad573cad796e8e247df7b796", + "reference": "9d3e80d54d9ae747ad573cad796e8e247df7b796", + "shasum": "" + }, + "require": { + "php": "^7.1", + "psr/http-message": "^1.0", + "symfony/http-foundation": "^4.4 || ^5.0" + }, + "require-dev": { + "nyholm/psr7": "^1.1", + "symfony/phpunit-bridge": "^4.4 || ^5.0", + "zendframework/zend-diactoros": "^1.4.1 || ^2.0" + }, + "suggest": { + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" + }, + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bridge\\PsrHttpMessage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "PSR HTTP message bridge", + "homepage": "http://symfony.com", + "keywords": [ + "http", + "http-message", + "psr-17", + "psr-7" + ], + "time": "2019-11-25T19:33:50+00:00" + }, { "name": "web-auth/cose-lib", "version": "v2.1.7", diff --git a/lam/lib/2factor.inc b/lam/lib/2factor.inc index b50c8c31..677e1ef9 100644 --- a/lam/lib/2factor.inc +++ b/lam/lib/2factor.inc @@ -10,6 +10,7 @@ use \htmlJavaScript; use \htmlStatusMessage; use \htmlDiv; use \LAMException; +use Webauthn\PublicKeyCredentialCreationOptions; use function LAM\LOGIN\WEBAUTHN\storeNewRegistration; /* @@ -543,9 +544,8 @@ class WebauthnProvider extends BaseProvider { public function verify2ndFactor($user, $password, $serial, $twoFactorInput) { logNewMessage(LOG_DEBUG, 'WebauthnProvider: Checking 2nd factor for ' . $user); $response = base64_decode($_POST['sig_response']); - include_once __DIR__ . '/3rdParty/composer/autoload.php'; include_once __DIR__ . '/webauthn.inc'; - $registrationObject = $_SESSION['webauthn_registration']; + $registrationObject = PublicKeyCredentialCreationOptions::createFromString($_SESSION['webauthn_registration']); if (storeNewRegistration($registrationObject, $response)) { return true; } diff --git a/lam/lib/3rdParty/composer/composer/autoload_files.php b/lam/lib/3rdParty/composer/composer/autoload_files.php index d58d66de..ada90386 100644 --- a/lam/lib/3rdParty/composer/composer/autoload_files.php +++ b/lam/lib/3rdParty/composer/composer/autoload_files.php @@ -9,6 +9,6 @@ return array( '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', 'a4ecaeafb8cfb009ad0e052c90355e98' => $vendorDir . '/beberlei/assert/lib/Assert/functions.php', '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', - '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', ); diff --git a/lam/lib/3rdParty/composer/composer/autoload_psr4.php b/lam/lib/3rdParty/composer/composer/autoload_psr4.php index 5d88d7da..3248ceaa 100644 --- a/lam/lib/3rdParty/composer/composer/autoload_psr4.php +++ b/lam/lib/3rdParty/composer/composer/autoload_psr4.php @@ -14,6 +14,7 @@ return array( 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), 'Symfony\\Component\\Mime\\' => array($vendorDir . '/symfony/mime'), 'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'), + 'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'), 'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), diff --git a/lam/lib/3rdParty/composer/composer/autoload_static.php b/lam/lib/3rdParty/composer/composer/autoload_static.php index ab4e11ea..30a44942 100644 --- a/lam/lib/3rdParty/composer/composer/autoload_static.php +++ b/lam/lib/3rdParty/composer/composer/autoload_static.php @@ -10,8 +10,8 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', 'a4ecaeafb8cfb009ad0e052c90355e98' => __DIR__ . '/..' . '/beberlei/assert/lib/Assert/functions.php', '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', - '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', ); public static $prefixLengthsPsr4 = array ( @@ -28,6 +28,7 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 'Symfony\\Polyfill\\Ctype\\' => 23, 'Symfony\\Component\\Mime\\' => 23, 'Symfony\\Component\\HttpFoundation\\' => 33, + 'Symfony\\Bridge\\PsrHttpMessage\\' => 30, ), 'R' => array ( @@ -98,6 +99,10 @@ class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5 array ( 0 => __DIR__ . '/..' . '/symfony/http-foundation', ), + 'Symfony\\Bridge\\PsrHttpMessage\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/psr-http-message-bridge', + ), 'Ramsey\\Uuid\\' => array ( 0 => __DIR__ . '/..' . '/ramsey/uuid/src', diff --git a/lam/lib/3rdParty/composer/composer/installed.json b/lam/lib/3rdParty/composer/composer/installed.json index aada8d20..6363f5fb 100644 --- a/lam/lib/3rdParty/composer/composer/installed.json +++ b/lam/lib/3rdParty/composer/composer/installed.json @@ -783,8 +783,8 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.13.0", - "version_normalized": "1.13.0.0", + "version": "v1.13.1", + "version_normalized": "1.13.1.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -843,8 +843,8 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.13.0", - "version_normalized": "1.13.0.0", + "version": "v1.13.1", + "version_normalized": "1.13.1.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -907,8 +907,8 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.13.0", - "version_normalized": "1.13.0.0", + "version": "v1.13.1", + "version_normalized": "1.13.1.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -968,8 +968,8 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.13.0", - "version_normalized": "1.13.0.0", + "version": "v1.13.1", + "version_normalized": "1.13.1.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", @@ -1023,6 +1023,73 @@ "shim" ] }, + { + "name": "symfony/psr-http-message-bridge", + "version": "v1.3.0", + "version_normalized": "1.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/psr-http-message-bridge.git", + "reference": "9d3e80d54d9ae747ad573cad796e8e247df7b796" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/9d3e80d54d9ae747ad573cad796e8e247df7b796", + "reference": "9d3e80d54d9ae747ad573cad796e8e247df7b796", + "shasum": "" + }, + "require": { + "php": "^7.1", + "psr/http-message": "^1.0", + "symfony/http-foundation": "^4.4 || ^5.0" + }, + "require-dev": { + "nyholm/psr7": "^1.1", + "symfony/phpunit-bridge": "^4.4 || ^5.0", + "zendframework/zend-diactoros": "^1.4.1 || ^2.0" + }, + "suggest": { + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" + }, + "time": "2019-11-25T19:33:50+00:00", + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\PsrHttpMessage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "PSR HTTP message bridge", + "homepage": "http://symfony.com", + "keywords": [ + "http", + "http-message", + "psr-17", + "psr-7" + ] + }, { "name": "web-auth/cose-lib", "version": "v2.1.7", diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.gitignore b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.gitignore new file mode 100644 index 00000000..082fd221 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.gitignore @@ -0,0 +1,5 @@ +vendor/ +composer.lock +phpunit.xml +.php_cs.cache +.phpunit.result.cache diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.php_cs.dist b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.php_cs.dist new file mode 100644 index 00000000..d741d39f --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.php_cs.dist @@ -0,0 +1,24 @@ +setRules([ + '@Symfony' => true, + '@Symfony:risky' => true, + '@PHPUnit48Migration:risky' => true, + 'php_unit_no_expectation_annotation' => false, // part of `PHPUnitXYMigration:risky` ruleset, to be enabled when PHPUnit 4.x support will be dropped, as we don't want to rewrite exceptions handling twice + 'array_syntax' => ['syntax' => 'short'], + 'fopen_flags' => false, + 'ordered_imports' => true, + 'protected_to_private' => false, + // Part of @Symfony:risky in PHP-CS-Fixer 2.13.0. To be removed from the config file once upgrading + 'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'namespaced'], + // Part of future @Symfony ruleset in PHP-CS-Fixer To be removed from the config file once upgrading + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + ]) + ->setRiskyAllowed(true) + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__) + ->name('*.php') + ) +; diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.travis.yml b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.travis.yml new file mode 100644 index 00000000..d171c003 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/.travis.yml @@ -0,0 +1,48 @@ +language: php +sudo: false +cache: + directories: + - $HOME/.composer/cache/files + - $HOME/symfony-bridge/.phpunit + +env: + global: + - PHPUNIT_FLAGS="-v" + - SYMFONY_PHPUNIT_DIR="$HOME/symfony-bridge/.phpunit" + +matrix: + fast_finish: true + include: + # Minimum supported dependencies with the latest and oldest PHP version + - php: 7.3 + env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="weak_vendors" + + - php: 7.1 + - php: 7.2 + - php: 7.3 + env: COVERAGE=true PHPUNIT_FLAGS="-v --coverage-text" + + # Latest commit to master + - php: 7.3 + env: STABILITY="dev" + + allow_failures: + # Dev-master is allowed to fail. + - env: STABILITY="dev" + +before_install: + - if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi + - if ! [ -z "$STABILITY" ]; then composer config minimum-stability ${STABILITY}; fi; + - if ! [ -v "$DEPENDENCIES" ]; then composer require --no-update ${DEPENDENCIES}; fi; + +install: + # To be removed when this issue will be resolved: https://github.com/composer/composer/issues/5355 + - if [[ "$COMPOSER_FLAGS" == *"--prefer-lowest"* ]]; then composer update --prefer-dist --no-interaction --prefer-stable --quiet; fi + - composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction + - ./vendor/bin/simple-phpunit install + +script: + - composer validate --strict --no-check-lock + # simple-phpunit is the PHPUnit wrapper provided by the PHPUnit Bridge component and + # it helps with testing legacy code and deprecations (composer require symfony/phpunit-bridge) + - ./vendor/bin/simple-phpunit $PHPUNIT_FLAGS diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/CHANGELOG.md b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/CHANGELOG.md new file mode 100644 index 00000000..1559be28 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/CHANGELOG.md @@ -0,0 +1,40 @@ +CHANGELOG +========= + +* 1.3.0 (2019-11-25) + + * Added support for streamed requests + * Added support for Symfony 5.0+ + * Fixed bridging UploadedFile objects + * Bumped minimum version of Symfony to 4.4 + +* 1.2.0 (2019-03-11) + + * Added new documentation links + * Bumped minimum version of PHP to 7.1 + * Added support for streamed responses + +* 1.1.2 (2019-04-03) + + * Fixed createResponse + +* 1.1.1 (2019-03-11) + + * Deprecated DiactorosFactory, use PsrHttpFactory instead + * Removed triggering of deprecation + +* 1.1.0 (2018-08-30) + + * Added support for creating PSR-7 messages using PSR-17 factories + +* 1.0.2 (2017-12-19) + + * Fixed request target in PSR7 Request (mtibben) + +* 1.0.1 (2017-12-04) + + * Added support for Symfony 4 (dunglas) + +* 1.0.0 (2016-09-14) + + * Initial release diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/DiactorosFactory.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/DiactorosFactory.php new file mode 100644 index 00000000..cc87dd82 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/DiactorosFactory.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Factory; + +@trigger_error(sprintf('The "%s" class is deprecated since symfony/psr-http-message-bridge 1.2, use PsrHttpFactory instead.', DiactorosFactory::class), E_USER_DEPRECATED); + +use Psr\Http\Message\UploadedFileInterface; +use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; +use Zend\Diactoros\Response as DiactorosResponse; +use Zend\Diactoros\ServerRequest; +use Zend\Diactoros\ServerRequestFactory as DiactorosRequestFactory; +use Zend\Diactoros\Stream as DiactorosStream; +use Zend\Diactoros\UploadedFile as DiactorosUploadedFile; + +/** + * Builds Psr\HttpMessage instances using the Zend Diactoros implementation. + * + * @author Kévin Dunglas + * + * @deprecated since symfony/psr-http-message-bridge 1.2, use PsrHttpFactory instead + */ +class DiactorosFactory implements HttpMessageFactoryInterface +{ + public function __construct() + { + if (!class_exists('Zend\Diactoros\ServerRequestFactory')) { + throw new \RuntimeException('Zend Diactoros must be installed to use the DiactorosFactory.'); + } + } + + /** + * {@inheritdoc} + */ + public function createRequest(Request $symfonyRequest) + { + $server = method_exists('Zend\Diactoros\ServerRequestFactory', 'normalizeServer') + ? DiactorosRequestFactory::normalizeServer($symfonyRequest->server->all()) + : \Zend\Diactoros\normalizeServer($symfonyRequest->server->all()); + $headers = $symfonyRequest->headers->all(); + + $body = new DiactorosStream($symfonyRequest->getContent(true)); + + $files = method_exists('Zend\Diactoros\ServerRequestFactory', 'normalizeFiles') + ? DiactorosRequestFactory::normalizeFiles($this->getFiles($symfonyRequest->files->all())) + : \Zend\Diactoros\normalizeUploadedFiles($this->getFiles($symfonyRequest->files->all())); + + $request = new ServerRequest( + $server, + $files, + $symfonyRequest->getSchemeAndHttpHost().$symfonyRequest->getRequestUri(), + $symfonyRequest->getMethod(), + $body, + $headers + ); + + $request = $request + ->withCookieParams($symfonyRequest->cookies->all()) + ->withQueryParams($symfonyRequest->query->all()) + ->withParsedBody($symfonyRequest->request->all()) + ->withRequestTarget($symfonyRequest->getRequestUri()) + ; + + foreach ($symfonyRequest->attributes->all() as $key => $value) { + $request = $request->withAttribute($key, $value); + } + + return $request; + } + + /** + * Converts Symfony uploaded files array to the PSR one. + * + * @return array + */ + private function getFiles(array $uploadedFiles) + { + $files = []; + + foreach ($uploadedFiles as $key => $value) { + if (null === $value) { + $files[$key] = new DiactorosUploadedFile(null, 0, UPLOAD_ERR_NO_FILE, null, null); + continue; + } + if ($value instanceof UploadedFile) { + $files[$key] = $this->createUploadedFile($value); + } else { + $files[$key] = $this->getFiles($value); + } + } + + return $files; + } + + /** + * Creates a PSR-7 UploadedFile instance from a Symfony one. + * + * @return UploadedFileInterface + */ + private function createUploadedFile(UploadedFile $symfonyUploadedFile) + { + return new DiactorosUploadedFile( + $symfonyUploadedFile->getRealPath(), + (int) $symfonyUploadedFile->getSize(), + $symfonyUploadedFile->getError(), + $symfonyUploadedFile->getClientOriginalName(), + $symfonyUploadedFile->getClientMimeType() + ); + } + + /** + * {@inheritdoc} + */ + public function createResponse(Response $symfonyResponse) + { + if ($symfonyResponse instanceof BinaryFileResponse) { + $stream = new DiactorosStream($symfonyResponse->getFile()->getPathname(), 'r'); + } else { + $stream = new DiactorosStream('php://temp', 'wb+'); + if ($symfonyResponse instanceof StreamedResponse) { + ob_start(function ($buffer) use ($stream) { + $stream->write($buffer); + + return ''; + }); + + $symfonyResponse->sendContent(); + ob_end_clean(); + } else { + $stream->write($symfonyResponse->getContent()); + } + } + + $headers = $symfonyResponse->headers->all(); + if (!isset($headers['Set-Cookie']) && !isset($headers['set-cookie'])) { + $cookies = $symfonyResponse->headers->getCookies(); + if (!empty($cookies)) { + $headers['Set-Cookie'] = []; + foreach ($cookies as $cookie) { + $headers['Set-Cookie'][] = $cookie->__toString(); + } + } + } + + $response = new DiactorosResponse( + $stream, + $symfonyResponse->getStatusCode(), + $headers + ); + + $protocolVersion = $symfonyResponse->getProtocolVersion(); + if ('1.1' !== $protocolVersion) { + $response = $response->withProtocolVersion($protocolVersion); + } + + return $response; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/HttpFoundationFactory.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/HttpFoundationFactory.php new file mode 100644 index 00000000..d9bbaf2d --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/HttpFoundationFactory.php @@ -0,0 +1,240 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Factory; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UploadedFileInterface; +use Psr\Http\Message\UriInterface; +use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; + +/** + * {@inheritdoc} + * + * @author Kévin Dunglas + */ +class HttpFoundationFactory implements HttpFoundationFactoryInterface +{ + /** + * @var int The maximum output buffering size for each iteration when sending the response + */ + private $responseBufferMaxLength; + + public function __construct(int $responseBufferMaxLength = 16372) + { + $this->responseBufferMaxLength = $responseBufferMaxLength; + } + + /** + * {@inheritdoc} + */ + public function createRequest(ServerRequestInterface $psrRequest, bool $streamed = false) + { + $server = []; + $uri = $psrRequest->getUri(); + + if ($uri instanceof UriInterface) { + $server['SERVER_NAME'] = $uri->getHost(); + $server['SERVER_PORT'] = $uri->getPort(); + $server['REQUEST_URI'] = $uri->getPath(); + $server['QUERY_STRING'] = $uri->getQuery(); + } + + $server['REQUEST_METHOD'] = $psrRequest->getMethod(); + + $server = array_replace($server, $psrRequest->getServerParams()); + + $parsedBody = $psrRequest->getParsedBody(); + $parsedBody = \is_array($parsedBody) ? $parsedBody : []; + + $request = new Request( + $psrRequest->getQueryParams(), + $parsedBody, + $psrRequest->getAttributes(), + $psrRequest->getCookieParams(), + $this->getFiles($psrRequest->getUploadedFiles()), + $server, + $streamed ? $psrRequest->getBody()->detach() : $psrRequest->getBody()->__toString() + ); + $request->headers->replace($psrRequest->getHeaders()); + + return $request; + } + + /** + * Converts to the input array to $_FILES structure. + */ + private function getFiles(array $uploadedFiles): array + { + $files = []; + + foreach ($uploadedFiles as $key => $value) { + if ($value instanceof UploadedFileInterface) { + $files[$key] = $this->createUploadedFile($value); + } else { + $files[$key] = $this->getFiles($value); + } + } + + return $files; + } + + /** + * Creates Symfony UploadedFile instance from PSR-7 ones. + */ + private function createUploadedFile(UploadedFileInterface $psrUploadedFile): UploadedFile + { + return new UploadedFile($psrUploadedFile, function () { return $this->getTemporaryPath(); }); + } + + /** + * Gets a temporary file path. + * + * @return string + */ + protected function getTemporaryPath() + { + return tempnam(sys_get_temp_dir(), uniqid('symfony', true)); + } + + /** + * {@inheritdoc} + */ + public function createResponse(ResponseInterface $psrResponse, bool $streamed = false) + { + $cookies = $psrResponse->getHeader('Set-Cookie'); + $psrResponse = $psrResponse->withoutHeader('Set-Cookie'); + + if ($streamed) { + $response = new StreamedResponse( + $this->createStreamedResponseCallback($psrResponse->getBody()), + $psrResponse->getStatusCode(), + $psrResponse->getHeaders() + ); + } else { + $response = new Response( + $psrResponse->getBody()->__toString(), + $psrResponse->getStatusCode(), + $psrResponse->getHeaders() + ); + } + + $response->setProtocolVersion($psrResponse->getProtocolVersion()); + + foreach ($cookies as $cookie) { + $response->headers->setCookie($this->createCookie($cookie)); + } + + return $response; + } + + /** + * Creates a Cookie instance from a cookie string. + * + * Some snippets have been taken from the Guzzle project: https://github.com/guzzle/guzzle/blob/5.3/src/Cookie/SetCookie.php#L34 + * + * @throws \InvalidArgumentException + */ + private function createCookie(string $cookie): Cookie + { + foreach (explode(';', $cookie) as $part) { + $part = trim($part); + + $data = explode('=', $part, 2); + $name = $data[0]; + $value = isset($data[1]) ? trim($data[1], " \n\r\t\0\x0B\"") : null; + + if (!isset($cookieName)) { + $cookieName = $name; + $cookieValue = $value; + + continue; + } + + if ('expires' === strtolower($name) && null !== $value) { + $cookieExpire = new \DateTime($value); + + continue; + } + + if ('path' === strtolower($name) && null !== $value) { + $cookiePath = $value; + + continue; + } + + if ('domain' === strtolower($name) && null !== $value) { + $cookieDomain = $value; + + continue; + } + + if ('secure' === strtolower($name)) { + $cookieSecure = true; + + continue; + } + + if ('httponly' === strtolower($name)) { + $cookieHttpOnly = true; + + continue; + } + + if ('samesite' === strtolower($name) && null !== $value) { + $samesite = $value; + + continue; + } + } + + if (!isset($cookieName)) { + throw new \InvalidArgumentException('The value of the Set-Cookie header is malformed.'); + } + + return new Cookie( + $cookieName, + $cookieValue, + isset($cookieExpire) ? $cookieExpire : 0, + isset($cookiePath) ? $cookiePath : '/', + isset($cookieDomain) ? $cookieDomain : null, + isset($cookieSecure), + isset($cookieHttpOnly), + false, + isset($samesite) ? $samesite : null + ); + } + + private function createStreamedResponseCallback(StreamInterface $body): callable + { + return function () use ($body) { + if ($body->isSeekable()) { + $body->rewind(); + } + + if (!$body->isReadable()) { + echo $body; + + return; + } + + while (!$body->eof()) { + echo $body->read($this->responseBufferMaxLength); + } + }; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php new file mode 100644 index 00000000..dfcfe73b --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php @@ -0,0 +1,168 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Factory; + +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ServerRequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\UploadedFileFactoryInterface; +use Psr\Http\Message\UploadedFileInterface; +use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; + +/** + * Builds Psr\HttpMessage instances using a PSR-17 implementation. + * + * @author Antonio J. García Lagar + */ +class PsrHttpFactory implements HttpMessageFactoryInterface +{ + private $serverRequestFactory; + private $streamFactory; + private $uploadedFileFactory; + private $responseFactory; + + public function __construct(ServerRequestFactoryInterface $serverRequestFactory, StreamFactoryInterface $streamFactory, UploadedFileFactoryInterface $uploadedFileFactory, ResponseFactoryInterface $responseFactory) + { + $this->serverRequestFactory = $serverRequestFactory; + $this->streamFactory = $streamFactory; + $this->uploadedFileFactory = $uploadedFileFactory; + $this->responseFactory = $responseFactory; + } + + /** + * {@inheritdoc} + */ + public function createRequest(Request $symfonyRequest) + { + $request = $this->serverRequestFactory->createServerRequest( + $symfonyRequest->getMethod(), + $symfonyRequest->getUri(), + $symfonyRequest->server->all() + ); + + foreach ($symfonyRequest->headers->all() as $name => $value) { + $request = $request->withHeader($name, $value); + } + + $body = $this->streamFactory->createStreamFromResource($symfonyRequest->getContent(true)); + + $request = $request + ->withBody($body) + ->withUploadedFiles($this->getFiles($symfonyRequest->files->all())) + ->withCookieParams($symfonyRequest->cookies->all()) + ->withQueryParams($symfonyRequest->query->all()) + ->withParsedBody($symfonyRequest->request->all()) + ; + + foreach ($symfonyRequest->attributes->all() as $key => $value) { + $request = $request->withAttribute($key, $value); + } + + return $request; + } + + /** + * Converts Symfony uploaded files array to the PSR one. + * + * @return array + */ + private function getFiles(array $uploadedFiles) + { + $files = []; + + foreach ($uploadedFiles as $key => $value) { + if (null === $value) { + $files[$key] = $this->uploadedFileFactory->createUploadedFile($this->streamFactory->createStream(), 0, UPLOAD_ERR_NO_FILE); + continue; + } + if ($value instanceof UploadedFile) { + $files[$key] = $this->createUploadedFile($value); + } else { + $files[$key] = $this->getFiles($value); + } + } + + return $files; + } + + /** + * Creates a PSR-7 UploadedFile instance from a Symfony one. + * + * @return UploadedFileInterface + */ + private function createUploadedFile(UploadedFile $symfonyUploadedFile) + { + return $this->uploadedFileFactory->createUploadedFile( + $this->streamFactory->createStreamFromFile( + $symfonyUploadedFile->getRealPath() + ), + (int) $symfonyUploadedFile->getSize(), + $symfonyUploadedFile->getError(), + $symfonyUploadedFile->getClientOriginalName(), + $symfonyUploadedFile->getClientMimeType() + ); + } + + /** + * {@inheritdoc} + */ + public function createResponse(Response $symfonyResponse) + { + $response = $this->responseFactory->createResponse($symfonyResponse->getStatusCode(), Response::$statusTexts[$symfonyResponse->getStatusCode()] ?? ''); + + if ($symfonyResponse instanceof BinaryFileResponse) { + $stream = $this->streamFactory->createStreamFromFile( + $symfonyResponse->getFile()->getPathname() + ); + } else { + $stream = $this->streamFactory->createStreamFromFile('php://temp', 'wb+'); + if ($symfonyResponse instanceof StreamedResponse) { + ob_start(function ($buffer) use ($stream) { + $stream->write($buffer); + + return ''; + }); + + $symfonyResponse->sendContent(); + ob_end_clean(); + } else { + $stream->write($symfonyResponse->getContent()); + } + } + + $response = $response->withBody($stream); + + $headers = $symfonyResponse->headers->all(); + $cookies = $symfonyResponse->headers->getCookies(); + if (!empty($cookies)) { + $headers['Set-Cookie'] = []; + + foreach ($cookies as $cookie) { + $headers['Set-Cookie'][] = $cookie->__toString(); + } + } + + foreach ($headers as $name => $value) { + $response = $response->withHeader($name, $value); + } + + $protocolVersion = $symfonyResponse->getProtocolVersion(); + $response = $response->withProtocolVersion($protocolVersion); + + return $response; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/UploadedFile.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/UploadedFile.php new file mode 100644 index 00000000..804f7478 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Factory/UploadedFile.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Factory; + +use Psr\Http\Message\UploadedFileInterface; +use Symfony\Component\HttpFoundation\File\Exception\FileException; +use Symfony\Component\HttpFoundation\File\File; +use Symfony\Component\HttpFoundation\File\UploadedFile as BaseUploadedFile; + +/** + * @author Nicolas Grekas + */ +class UploadedFile extends BaseUploadedFile +{ + private $psrUploadedFile; + private $test = false; + + public function __construct(UploadedFileInterface $psrUploadedFile, callable $getTemporaryPath) + { + $error = $psrUploadedFile->getError(); + $path = ''; + + if (UPLOAD_ERR_NO_FILE !== $error) { + $path = $psrUploadedFile->getStream()->getMetadata('uri') ?? ''; + + if ($this->test = !\is_string($path) || !is_uploaded_file($path)) { + $path = $getTemporaryPath(); + $psrUploadedFile->moveTo($path); + } + } + + parent::__construct( + $path, + (string) $psrUploadedFile->getClientFilename(), + $psrUploadedFile->getClientMediaType(), + $psrUploadedFile->getError(), + $this->test + ); + + $this->psrUploadedFile = $psrUploadedFile; + } + + /** + * {@inheritdoc} + */ + public function move($directory, $name = null): File + { + if (!$this->isValid() || $this->test) { + return parent::move($directory, $name); + } + + $target = $this->getTargetFile($directory, $name); + + try { + $this->psrUploadedFile->moveTo($target); + } catch (\RuntimeException $e) { + throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, $e->getMessage()), 0, $e); + } + + @chmod($target, 0666 & ~umask()); + + return $target; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/HttpFoundationFactoryInterface.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/HttpFoundationFactoryInterface.php new file mode 100644 index 00000000..a3f90438 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/HttpFoundationFactoryInterface.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * Creates Symfony Request and Response instances from PSR-7 ones. + * + * @author Kévin Dunglas + */ +interface HttpFoundationFactoryInterface +{ + /** + * Creates a Symfony Request instance from a PSR-7 one. + * + * @return Request + */ + public function createRequest(ServerRequestInterface $psrRequest, bool $streamed = false); + + /** + * Creates a Symfony Response instance from a PSR-7 one. + * + * @return Response + */ + public function createResponse(ResponseInterface $psrResponse, bool $streamed = false); +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/HttpMessageFactoryInterface.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/HttpMessageFactoryInterface.php new file mode 100644 index 00000000..f7b964e1 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/HttpMessageFactoryInterface.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * Creates PSR HTTP Request and Response instances from Symfony ones. + * + * @author Kévin Dunglas + */ +interface HttpMessageFactoryInterface +{ + /** + * Creates a PSR-7 Request instance from a Symfony one. + * + * @return ServerRequestInterface + */ + public function createRequest(Request $symfonyRequest); + + /** + * Creates a PSR-7 Response instance from a Symfony one. + * + * @return ResponseInterface + */ + public function createResponse(Response $symfonyResponse); +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/LICENSE b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/LICENSE new file mode 100644 index 00000000..12a74531 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2016 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. diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/README.md b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/README.md new file mode 100644 index 00000000..87fbd43a --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/README.md @@ -0,0 +1,20 @@ +PSR-7 Bridge +============ + +Provides integration for PSR7. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/psr7.html) + * [SensioFrameworkExtraBundle](https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html#psr-7-support) + +Running the tests +----------------- + +If you want to run the unit tests, install dev dependencies before +running PHPUnit: + + $ cd path/to/Symfony/Bridge/PsrHttpMessage/ + $ composer.phar install + $ phpunit diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/AbstractHttpMessageFactoryTest.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/AbstractHttpMessageFactoryTest.php new file mode 100644 index 00000000..998edcc2 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/AbstractHttpMessageFactoryTest.php @@ -0,0 +1,217 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Factory; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; + +/** + * @author Kévin Dunglas + * @author Antonio J. García Lagar + */ +abstract class AbstractHttpMessageFactoryTest extends TestCase +{ + private $factory; + private $tmpDir; + + abstract protected function buildHttpMessageFactory(): HttpMessageFactoryInterface; + + public function setUp(): void + { + $this->factory = $this->buildHttpMessageFactory(); + $this->tmpDir = sys_get_temp_dir(); + } + + public function testCreateRequest() + { + $stdClass = new \stdClass(); + $request = new Request( + [ + 'bar' => ['baz' => '42'], + 'foo' => '1', + ], + [ + 'twitter' => [ + '@dunglas' => 'Kévin Dunglas', + '@coopTilleuls' => 'Les-Tilleuls.coop', + ], + 'baz' => '2', + ], + [ + 'a1' => $stdClass, + 'a2' => ['foo' => 'bar'], + ], + [ + 'c1' => 'foo', + 'c2' => ['c3' => 'bar'], + ], + [ + 'f1' => $this->createUploadedFile('F1', 'f1.txt', 'text/plain', UPLOAD_ERR_OK), + 'foo' => ['f2' => $this->createUploadedFile('F2', 'f2.txt', 'text/plain', UPLOAD_ERR_OK)], + ], + [ + 'REQUEST_METHOD' => 'POST', + 'HTTP_HOST' => 'dunglas.fr', + 'HTTP_X_SYMFONY' => '2.8', + 'REQUEST_URI' => '/testCreateRequest?bar[baz]=42&foo=1', + 'QUERY_STRING' => 'bar[baz]=42&foo=1', + ], + 'Content' + ); + + $psrRequest = $this->factory->createRequest($request); + + $this->assertEquals('Content', $psrRequest->getBody()->__toString()); + + $queryParams = $psrRequest->getQueryParams(); + $this->assertEquals('1', $queryParams['foo']); + $this->assertEquals('42', $queryParams['bar']['baz']); + + $requestTarget = $psrRequest->getRequestTarget(); + $this->assertEquals('/testCreateRequest?bar[baz]=42&foo=1', urldecode($requestTarget)); + + $parsedBody = $psrRequest->getParsedBody(); + $this->assertEquals('Kévin Dunglas', $parsedBody['twitter']['@dunglas']); + $this->assertEquals('Les-Tilleuls.coop', $parsedBody['twitter']['@coopTilleuls']); + $this->assertEquals('2', $parsedBody['baz']); + + $attributes = $psrRequest->getAttributes(); + $this->assertEquals($stdClass, $attributes['a1']); + $this->assertEquals('bar', $attributes['a2']['foo']); + + $cookies = $psrRequest->getCookieParams(); + $this->assertEquals('foo', $cookies['c1']); + $this->assertEquals('bar', $cookies['c2']['c3']); + + $uploadedFiles = $psrRequest->getUploadedFiles(); + $this->assertEquals('F1', $uploadedFiles['f1']->getStream()->__toString()); + $this->assertEquals('f1.txt', $uploadedFiles['f1']->getClientFilename()); + $this->assertEquals('text/plain', $uploadedFiles['f1']->getClientMediaType()); + $this->assertEquals(UPLOAD_ERR_OK, $uploadedFiles['f1']->getError()); + + $this->assertEquals('F2', $uploadedFiles['foo']['f2']->getStream()->__toString()); + $this->assertEquals('f2.txt', $uploadedFiles['foo']['f2']->getClientFilename()); + $this->assertEquals('text/plain', $uploadedFiles['foo']['f2']->getClientMediaType()); + $this->assertEquals(UPLOAD_ERR_OK, $uploadedFiles['foo']['f2']->getError()); + + $serverParams = $psrRequest->getServerParams(); + $this->assertEquals('POST', $serverParams['REQUEST_METHOD']); + $this->assertEquals('2.8', $serverParams['HTTP_X_SYMFONY']); + $this->assertEquals('POST', $psrRequest->getMethod()); + $this->assertEquals(['2.8'], $psrRequest->getHeader('X-Symfony')); + } + + public function testGetContentCanBeCalledAfterRequestCreation() + { + $header = ['HTTP_HOST' => 'dunglas.fr']; + $request = new Request([], [], [], [], [], $header, 'Content'); + + $psrRequest = $this->factory->createRequest($request); + + $this->assertEquals('Content', $psrRequest->getBody()->__toString()); + $this->assertEquals('Content', $request->getContent()); + } + + private function createUploadedFile($content, $originalName, $mimeType, $error) + { + $path = tempnam($this->tmpDir, uniqid()); + file_put_contents($path, $content); + + return new UploadedFile($path, $originalName, $mimeType, $error, true); + } + + public function testCreateResponse() + { + $response = new Response( + 'Response content.', + 202, + ['X-Symfony' => ['3.4']] + ); + $response->headers->setCookie(new Cookie('city', 'Lille', new \DateTime('Wed, 13 Jan 2021 22:23:01 GMT'), '/', null, false, true, false, 'lax')); + + $psrResponse = $this->factory->createResponse($response); + $this->assertEquals('Response content.', $psrResponse->getBody()->__toString()); + $this->assertEquals(202, $psrResponse->getStatusCode()); + $this->assertEquals(['3.4'], $psrResponse->getHeader('X-Symfony')); + + $cookieHeader = $psrResponse->getHeader('Set-Cookie'); + $this->assertIsArray($cookieHeader); + $this->assertCount(1, $cookieHeader); + $this->assertRegExp('{city=Lille; expires=Wed, 13-Jan-2021 22:23:01 GMT;( max-age=\d+;)? path=/; httponly}i', $cookieHeader[0]); + } + + public function testCreateResponseFromStreamed() + { + $response = new StreamedResponse(function () { + echo "Line 1\n"; + flush(); + + echo "Line 2\n"; + flush(); + }); + + $psrResponse = $this->factory->createResponse($response); + + $this->assertEquals("Line 1\nLine 2\n", $psrResponse->getBody()->__toString()); + } + + public function testCreateResponseFromBinaryFile() + { + $path = tempnam($this->tmpDir, uniqid()); + file_put_contents($path, 'Binary'); + + $response = new BinaryFileResponse($path); + + $psrResponse = $this->factory->createResponse($response); + + $this->assertEquals('Binary', $psrResponse->getBody()->__toString()); + } + + public function testUploadErrNoFile() + { + $file = new UploadedFile('', '', null, UPLOAD_ERR_NO_FILE, true); + + $this->assertEquals(0, $file->getSize()); + $this->assertEquals(UPLOAD_ERR_NO_FILE, $file->getError()); + $this->assertFalse($file->getSize(), 'SplFile::getSize() returns false on error'); + + $request = new Request( + [], + [], + [], + [], + [ + 'f1' => $file, + 'f2' => ['name' => null, 'type' => null, 'tmp_name' => null, 'error' => UPLOAD_ERR_NO_FILE, 'size' => 0], + ], + [ + 'REQUEST_METHOD' => 'POST', + 'HTTP_HOST' => 'dunglas.fr', + 'HTTP_X_SYMFONY' => '2.8', + ], + 'Content' + ); + + $psrRequest = $this->factory->createRequest($request); + + $uploadedFiles = $psrRequest->getUploadedFiles(); + + $this->assertEquals(UPLOAD_ERR_NO_FILE, $uploadedFiles['f1']->getError()); + $this->assertEquals(UPLOAD_ERR_NO_FILE, $uploadedFiles['f2']->getError()); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/DiactorosFactoryTest.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/DiactorosFactoryTest.php new file mode 100644 index 00000000..9d0fc059 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/DiactorosFactoryTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Factory; + +use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory; +use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; + +/** + * @author Kévin Dunglas + * @author Antonio J. García Lagar + * + * @group legacy + */ +class DiactorosFactoryTest extends AbstractHttpMessageFactoryTest +{ + protected function buildHttpMessageFactory(): HttpMessageFactoryInterface + { + if (!class_exists('Zend\Diactoros\ServerRequestFactory')) { + $this->markTestSkipped('Zend Diactoros is not installed.'); + } + + return new DiactorosFactory(); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/HttpFoundationFactoryTest.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/HttpFoundationFactoryTest.php new file mode 100644 index 00000000..e35a7893 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/HttpFoundationFactoryTest.php @@ -0,0 +1,272 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Factory; + +use PHPUnit\Framework\TestCase; +use Psr\Http\Message\UploadedFileInterface; +use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; +use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\Response; +use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\ServerRequest; +use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\Stream; +use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\UploadedFile; +use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\Uri; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\File\Exception\FileException; +use Symfony\Component\HttpFoundation\File\UploadedFile as HttpFoundationUploadedFile; + +/** + * @author Kévin Dunglas + */ +class HttpFoundationFactoryTest extends TestCase +{ + /** @var HttpFoundationFactory */ + private $factory; + + /** @var string */ + private $tmpDir; + + public function setUp(): void + { + $this->factory = new HttpFoundationFactory(); + $this->tmpDir = sys_get_temp_dir(); + } + + public function testCreateRequest() + { + $stdClass = new \stdClass(); + $serverRequest = new ServerRequest( + '1.1', + [ + 'X-Dunglas-API-Platform' => '1.0', + 'X-data' => ['a', 'b'], + ], + new Stream('The body'), + '/about/kevin', + 'GET', + 'http://les-tilleuls.coop/about/kevin', + ['country' => 'France'], + ['city' => 'Lille'], + ['url' => 'http://les-tilleuls.coop'], + [ + 'doc1' => $this->createUploadedFile('Doc 1', UPLOAD_ERR_OK, 'doc1.txt', 'text/plain'), + 'nested' => [ + 'docs' => [ + $this->createUploadedFile('Doc 2', UPLOAD_ERR_OK, 'doc2.txt', 'text/plain'), + $this->createUploadedFile('Doc 3', UPLOAD_ERR_OK, 'doc3.txt', 'text/plain'), + ], + ], + ], + ['url' => 'http://dunglas.fr'], + ['custom' => $stdClass] + ); + + $symfonyRequest = $this->factory->createRequest($serverRequest); + $files = $symfonyRequest->files->all(); + + $this->assertEquals('http://les-tilleuls.coop', $symfonyRequest->query->get('url')); + $this->assertEquals('doc1.txt', $files['doc1']->getClientOriginalName()); + $this->assertEquals('doc2.txt', $files['nested']['docs'][0]->getClientOriginalName()); + $this->assertEquals('doc3.txt', $files['nested']['docs'][1]->getClientOriginalName()); + $this->assertEquals('http://dunglas.fr', $symfonyRequest->request->get('url')); + $this->assertEquals($stdClass, $symfonyRequest->attributes->get('custom')); + $this->assertEquals('Lille', $symfonyRequest->cookies->get('city')); + $this->assertEquals('France', $symfonyRequest->server->get('country')); + $this->assertEquals('The body', $symfonyRequest->getContent()); + $this->assertEquals('1.0', $symfonyRequest->headers->get('X-Dunglas-API-Platform')); + $this->assertEquals(['a', 'b'], $symfonyRequest->headers->all('X-data')); + } + + public function testCreateRequestWithStreamedBody() + { + $serverRequest = new ServerRequest( + '1.1', + [], + new Stream('The body'), + '/', + 'GET', + null, + [], + [], + [], + [], + null, + [] + ); + + $symfonyRequest = $this->factory->createRequest($serverRequest, true); + $this->assertEquals('The body', $symfonyRequest->getContent()); + } + + public function testCreateRequestWithNullParsedBody() + { + $serverRequest = new ServerRequest( + '1.1', + [], + new Stream(), + '/', + 'GET', + null, + [], + [], + [], + [], + null, + [] + ); + + $this->assertCount(0, $this->factory->createRequest($serverRequest)->request); + } + + public function testCreateRequestWithObjectParsedBody() + { + $serverRequest = new ServerRequest( + '1.1', + [], + new Stream(), + '/', + 'GET', + null, + [], + [], + [], + [], + new \stdClass(), + [] + ); + + $this->assertCount(0, $this->factory->createRequest($serverRequest)->request); + } + + public function testCreateRequestWithUri() + { + $serverRequest = new ServerRequest( + '1.1', + [], + new Stream(), + '/', + 'GET', + new Uri('http://les-tilleuls.coop/about/kevin'), + [], + [], + [], + [], + null, + [] + ); + + $this->assertEquals('/about/kevin', $this->factory->createRequest($serverRequest)->getPathInfo()); + } + + public function testCreateUploadedFile() + { + $uploadedFile = $this->createUploadedFile('An uploaded file.', UPLOAD_ERR_OK, 'myfile.txt', 'text/plain'); + $symfonyUploadedFile = $this->callCreateUploadedFile($uploadedFile); + $size = $symfonyUploadedFile->getSize(); + + $uniqid = uniqid(); + $symfonyUploadedFile->move($this->tmpDir, $uniqid); + + $this->assertEquals($uploadedFile->getSize(), $size); + $this->assertEquals(UPLOAD_ERR_OK, $symfonyUploadedFile->getError()); + $this->assertEquals('myfile.txt', $symfonyUploadedFile->getClientOriginalName()); + $this->assertEquals('txt', $symfonyUploadedFile->getClientOriginalExtension()); + $this->assertEquals('text/plain', $symfonyUploadedFile->getClientMimeType()); + $this->assertEquals('An uploaded file.', file_get_contents($this->tmpDir.'/'.$uniqid)); + } + + public function testCreateUploadedFileWithError() + { + $this->expectException(FileException::class); + $this->expectExceptionMessage('The file "e" could not be written on disk.'); + + $uploadedFile = $this->createUploadedFile('Error.', UPLOAD_ERR_CANT_WRITE, 'e', 'text/plain'); + $symfonyUploadedFile = $this->callCreateUploadedFile($uploadedFile); + + $this->assertEquals(UPLOAD_ERR_CANT_WRITE, $symfonyUploadedFile->getError()); + + $symfonyUploadedFile->move($this->tmpDir, 'shouldFail.txt'); + } + + private function createUploadedFile($content, $error, $clientFileName, $clientMediaType): UploadedFile + { + $filePath = tempnam($this->tmpDir, uniqid()); + file_put_contents($filePath, $content); + + return new UploadedFile($filePath, filesize($filePath), $error, $clientFileName, $clientMediaType); + } + + private function callCreateUploadedFile(UploadedFileInterface $uploadedFile): HttpFoundationUploadedFile + { + $reflection = new \ReflectionClass($this->factory); + $createUploadedFile = $reflection->getMethod('createUploadedFile'); + $createUploadedFile->setAccessible(true); + + return $createUploadedFile->invokeArgs($this->factory, [$uploadedFile]); + } + + public function testCreateResponse() + { + $response = new Response( + '1.0', + [ + 'X-Symfony' => ['2.8'], + 'Set-Cookie' => [ + 'theme=light', + 'test', + 'ABC=AeD; Domain=dunglas.fr; Path=/kevin; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly; SameSite=Strict', + ], + ], + new Stream('The response body'), + 200 + ); + + $symfonyResponse = $this->factory->createResponse($response); + + $this->assertEquals('1.0', $symfonyResponse->getProtocolVersion()); + $this->assertEquals('2.8', $symfonyResponse->headers->get('X-Symfony')); + + $cookies = $symfonyResponse->headers->getCookies(); + $this->assertEquals('theme', $cookies[0]->getName()); + $this->assertEquals('light', $cookies[0]->getValue()); + $this->assertEquals(0, $cookies[0]->getExpiresTime()); + $this->assertNull($cookies[0]->getDomain()); + $this->assertEquals('/', $cookies[0]->getPath()); + $this->assertFalse($cookies[0]->isSecure()); + $this->assertFalse($cookies[0]->isHttpOnly()); + + $this->assertEquals('test', $cookies[1]->getName()); + $this->assertNull($cookies[1]->getValue()); + + $this->assertEquals('ABC', $cookies[2]->getName()); + $this->assertEquals('AeD', $cookies[2]->getValue()); + $this->assertEquals(strtotime('Wed, 13 Jan 2021 22:23:01 GMT'), $cookies[2]->getExpiresTime()); + $this->assertEquals('dunglas.fr', $cookies[2]->getDomain()); + $this->assertEquals('/kevin', $cookies[2]->getPath()); + $this->assertTrue($cookies[2]->isSecure()); + $this->assertTrue($cookies[2]->isHttpOnly()); + if (\defined('Symfony\Component\HttpFoundation\Cookie::SAMESITE_STRICT')) { + $this->assertEquals(Cookie::SAMESITE_STRICT, $cookies[2]->getSameSite()); + } + + $this->assertEquals('The response body', $symfonyResponse->getContent()); + $this->assertEquals(200, $symfonyResponse->getStatusCode()); + + $symfonyResponse = $this->factory->createResponse($response, true); + + ob_start(); + $symfonyResponse->sendContent(); + $sentContent = ob_get_clean(); + + $this->assertEquals('The response body', $sentContent); + $this->assertEquals(200, $symfonyResponse->getStatusCode()); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/PsrHttpFactoryTest.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/PsrHttpFactoryTest.php new file mode 100644 index 00000000..b47cefc1 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Factory/PsrHttpFactoryTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Factory; + +use Nyholm\Psr7\Factory\Psr17Factory; +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; +use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; + +/** + * @author Kévin Dunglas + * @author Antonio J. García Lagar + */ +class PsrHttpFactoryTest extends AbstractHttpMessageFactoryTest +{ + protected function buildHttpMessageFactory(): HttpMessageFactoryInterface + { + $factory = new Psr17Factory(); + + return new PsrHttpFactory($factory, $factory, $factory, $factory); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Message.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Message.php new file mode 100644 index 00000000..0cda6fcb --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Message.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; + +use Psr\Http\Message\MessageInterface; +use Psr\Http\Message\StreamInterface; + +/** + * Message. + * + * @author Kévin Dunglas + */ +class Message implements MessageInterface +{ + private $version = '1.1'; + private $headers = []; + private $body; + + public function __construct($version = '1.1', array $headers = [], StreamInterface $body = null) + { + $this->version = $version; + $this->headers = $headers; + $this->body = null === $body ? new Stream() : $body; + } + + public function getProtocolVersion() + { + return $this->version; + } + + public function withProtocolVersion($version) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function getHeaders() + { + return $this->headers; + } + + public function hasHeader($name) + { + return isset($this->headers[$name]); + } + + public function getHeader($name) + { + return $this->hasHeader($name) ? $this->headers[$name] : []; + } + + public function getHeaderLine($name) + { + return $this->hasHeader($name) ? implode(',', $this->headers[$name]) : ''; + } + + public function withHeader($name, $value) + { + $this->headers[$name] = (array) $value; + + return $this; + } + + public function withAddedHeader($name, $value) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function withoutHeader($name) + { + unset($this->headers[$name]); + + return $this; + } + + public function getBody() + { + return $this->body; + } + + public function withBody(StreamInterface $body) + { + throw new \BadMethodCallException('Not implemented.'); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Response.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Response.php new file mode 100644 index 00000000..a8907929 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Response.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; + +/** + * @author Kévin Dunglas + */ +class Response extends Message implements ResponseInterface +{ + private $statusCode; + + public function __construct($version = '1.1', array $headers = [], StreamInterface $body = null, $statusCode = 200) + { + parent::__construct($version, $headers, $body); + + $this->statusCode = $statusCode; + } + + public function getStatusCode() + { + return $this->statusCode; + } + + public function withStatus($code, $reasonPhrase = '') + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function getReasonPhrase() + { + throw new \BadMethodCallException('Not implemented.'); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/ServerRequest.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/ServerRequest.php new file mode 100644 index 00000000..88ec9843 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/ServerRequest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; + +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UriInterface; + +/** + * @author Kévin Dunglas + */ +class ServerRequest extends Message implements ServerRequestInterface +{ + private $requestTarget; + private $method; + private $uri; + private $server; + private $cookies; + private $query; + private $uploadedFiles; + private $data; + private $attributes; + + public function __construct($version = '1.1', array $headers = [], StreamInterface $body = null, $requestTarget = '/', $method = 'GET', $uri = null, array $server = [], array $cookies = [], array $query = [], array $uploadedFiles = [], $data = null, array $attributes = []) + { + parent::__construct($version, $headers, $body); + + $this->requestTarget = $requestTarget; + $this->method = $method; + $this->uri = $uri; + $this->server = $server; + $this->cookies = $cookies; + $this->query = $query; + $this->uploadedFiles = $uploadedFiles; + $this->data = $data; + $this->attributes = $attributes; + } + + public function getRequestTarget() + { + return $this->requestTarget; + } + + public function withRequestTarget($requestTarget) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function getMethod() + { + return $this->method; + } + + public function withMethod($method) + { + } + + public function getUri() + { + return $this->uri; + } + + public function withUri(UriInterface $uri, $preserveHost = false) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function getServerParams() + { + return $this->server; + } + + public function getCookieParams() + { + return $this->cookies; + } + + public function withCookieParams(array $cookies) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function getQueryParams() + { + return $this->query; + } + + public function withQueryParams(array $query) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function getUploadedFiles() + { + return $this->uploadedFiles; + } + + public function withUploadedFiles(array $uploadedFiles) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function getParsedBody() + { + return $this->data; + } + + public function withParsedBody($data) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function getAttributes() + { + return $this->attributes; + } + + public function getAttribute($name, $default = null) + { + return isset($this->attributes[$name]) ? $this->attributes[$name] : $default; + } + + public function withAttribute($name, $value) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function withoutAttribute($name) + { + throw new \BadMethodCallException('Not implemented.'); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Stream.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Stream.php new file mode 100644 index 00000000..06fff284 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Stream.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; + +use Psr\Http\Message\StreamInterface; + +/** + * @author Kévin Dunglas + */ +class Stream implements StreamInterface +{ + private $stringContent; + private $eof = true; + + public function __construct($stringContent = '') + { + $this->stringContent = $stringContent; + } + + public function __toString() + { + return $this->stringContent; + } + + public function close() + { + } + + public function detach() + { + return fopen('data://text/plain,'.$this->stringContent, 'r'); + } + + public function getSize() + { + } + + public function tell() + { + return 0; + } + + public function eof() + { + return $this->eof; + } + + public function isSeekable() + { + return true; + } + + public function seek($offset, $whence = SEEK_SET) + { + } + + public function rewind() + { + $this->eof = false; + } + + public function isWritable() + { + return false; + } + + public function write($string) + { + } + + public function isReadable() + { + return true; + } + + public function read($length) + { + $this->eof = true; + + return $this->stringContent; + } + + public function getContents() + { + return $this->stringContent; + } + + public function getMetadata($key = null) + { + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/UploadedFile.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/UploadedFile.php new file mode 100644 index 00000000..f58a4bd6 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/UploadedFile.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; + +use Psr\Http\Message\UploadedFileInterface; + +/** + * @author Kévin Dunglas + */ +class UploadedFile implements UploadedFileInterface +{ + private $filePath; + private $size; + private $error; + private $clientFileName; + private $clientMediaType; + + public function __construct($filePath, $size = null, $error = UPLOAD_ERR_OK, $clientFileName = null, $clientMediaType = null) + { + $this->filePath = $filePath; + $this->size = $size; + $this->error = $error; + $this->clientFileName = $clientFileName; + $this->clientMediaType = $clientMediaType; + } + + public function getStream() + { + return new Stream(file_get_contents($this->filePath)); + } + + public function moveTo($targetPath) + { + rename($this->filePath, $targetPath); + } + + public function getSize() + { + return $this->size; + } + + public function getError() + { + return $this->error; + } + + public function getClientFilename() + { + return $this->clientFileName; + } + + public function getClientMediaType() + { + return $this->clientMediaType; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Uri.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Uri.php new file mode 100644 index 00000000..f11c7e5b --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Fixtures/Uri.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; + +use Psr\Http\Message\UriInterface; + +/** + * @author Rougin Royce Gutib + */ +class Uri implements UriInterface +{ + private $scheme = ''; + private $userInfo = ''; + private $host = ''; + private $port; + private $path = ''; + private $query = ''; + private $fragment = ''; + private $uriString; + + public function __construct($uri = '') + { + $parts = parse_url($uri); + + $this->scheme = isset($parts['scheme']) ? $parts['scheme'] : ''; + $this->userInfo = isset($parts['user']) ? $parts['user'] : ''; + $this->host = isset($parts['host']) ? $parts['host'] : ''; + $this->port = isset($parts['port']) ? $parts['port'] : null; + $this->path = isset($parts['path']) ? $parts['path'] : ''; + $this->query = isset($parts['query']) ? $parts['query'] : ''; + $this->fragment = isset($parts['fragment']) ? $parts['fragment'] : ''; + $this->uriString = $uri; + } + + public function getScheme() + { + return $this->scheme; + } + + public function getAuthority() + { + if (empty($this->host)) { + return ''; + } + + $authority = $this->host; + + if (!empty($this->userInfo)) { + $authority = $this->userInfo.'@'.$authority; + } + + $authority .= ':'.$this->port; + + return $authority; + } + + public function getUserInfo() + { + return $this->userInfo; + } + + public function getHost() + { + return $this->host; + } + + public function getPort() + { + return $this->port; + } + + public function getPath() + { + return $this->path; + } + + public function getQuery() + { + return $this->query; + } + + public function getFragment() + { + return $this->fragment; + } + + public function withScheme($scheme) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function withUserInfo($user, $password = null) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function withHost($host) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function withPort($port) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function withPath($path) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function withQuery($query) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function withFragment($fragment) + { + throw new \BadMethodCallException('Not implemented.'); + } + + public function __toString() + { + return $this->uriString; + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Functional/CovertTest.php b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Functional/CovertTest.php new file mode 100644 index 00000000..137a1541 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/Tests/Functional/CovertTest.php @@ -0,0 +1,234 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PsrHttpMessage\Tests\Functional; + +use Nyholm\Psr7\Factory\Psr17Factory; +use Nyholm\Psr7\Response as Psr7Response; +use Nyholm\Psr7\ServerRequest as Psr7Request; +use Nyholm\Psr7\Stream as Psr7Stream; +use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; +use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; +use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * Test to convert a request/response back and forth to make sure we do not loose data. + * + * @author Tobias Nyholm + */ +class CovertTest extends TestCase +{ + private $tmpDir; + + public function setUp(): void + { + if (!class_exists('Nyholm\Psr7\ServerRequest')) { + $this->markTestSkipped('nyholm/psr7 is not installed.'); + } + + $this->tmpDir = sys_get_temp_dir(); + } + + /** + * @dataProvider requestProvider + * + * @param Request|ServerRequestInterface $request + * @param HttpFoundationFactoryInterface|HttpMessageFactoryInterface $firstFactory + * @param HttpFoundationFactoryInterface|HttpMessageFactoryInterface $secondFactory + */ + public function testConvertRequestMultipleTimes($request, $firstFactory, $secondFactory) + { + $temporaryRequest = $firstFactory->createRequest($request); + $finalRequest = $secondFactory->createRequest($temporaryRequest); + + if ($finalRequest instanceof Request) { + $this->assertEquals($request->getBasePath(), $finalRequest->getBasePath()); + $this->assertEquals($request->getBaseUrl(), $finalRequest->getBaseUrl()); + $this->assertEquals($request->getContent(), $finalRequest->getContent()); + $this->assertEquals($request->getEncodings(), $finalRequest->getEncodings()); + $this->assertEquals($request->getETags(), $finalRequest->getETags()); + $this->assertEquals($request->getHost(), $finalRequest->getHost()); + $this->assertEquals($request->getHttpHost(), $finalRequest->getHttpHost()); + $this->assertEquals($request->getMethod(), $finalRequest->getMethod()); + $this->assertEquals($request->getPassword(), $finalRequest->getPassword()); + $this->assertEquals($request->getPathInfo(), $finalRequest->getPathInfo()); + $this->assertEquals($request->getPort(), $finalRequest->getPort()); + $this->assertEquals($request->getProtocolVersion(), $finalRequest->getProtocolVersion()); + $this->assertEquals($request->getQueryString(), $finalRequest->getQueryString()); + $this->assertEquals($request->getRequestUri(), $finalRequest->getRequestUri()); + $this->assertEquals($request->getScheme(), $finalRequest->getScheme()); + $this->assertEquals($request->getSchemeAndHttpHost(), $finalRequest->getSchemeAndHttpHost()); + $this->assertEquals($request->getScriptName(), $finalRequest->getScriptName()); + $this->assertEquals($request->getUri(), $finalRequest->getUri()); + $this->assertEquals($request->getUser(), $finalRequest->getUser()); + $this->assertEquals($request->getUserInfo(), $finalRequest->getUserInfo()); + } elseif ($finalRequest instanceof ServerRequestInterface) { + $strToLower = function ($arr) { + foreach ($arr as $key => $value) { + yield strtolower($key) => $value; + } + }; + $this->assertEquals($request->getAttributes(), $finalRequest->getAttributes()); + $this->assertEquals($request->getCookieParams(), $finalRequest->getCookieParams()); + $this->assertEquals((array) $request->getParsedBody(), (array) $finalRequest->getParsedBody()); + $this->assertEquals($request->getQueryParams(), $finalRequest->getQueryParams()); + // PSR7 does not define a "withServerParams" so this is impossible to implement without knowing the PSR7 implementation. + //$this->assertEquals($request->getServerParams(), $finalRequest->getServerParams()); + $this->assertEquals($request->getUploadedFiles(), $finalRequest->getUploadedFiles()); + $this->assertEquals($request->getMethod(), $finalRequest->getMethod()); + $this->assertEquals($request->getRequestTarget(), $finalRequest->getRequestTarget()); + $this->assertEquals((string) $request->getUri(), (string) $finalRequest->getUri()); + $this->assertEquals((string) $request->getBody(), (string) $finalRequest->getBody()); + $this->assertEquals($strToLower($request->getHeaders()), $strToLower($finalRequest->getHeaders())); + $this->assertEquals($request->getProtocolVersion(), $finalRequest->getProtocolVersion()); + } else { + $this->fail('$finalRequest must be an instance of PSR7 or a HTTPFoundation request'); + } + } + + public function requestProvider() + { + $sfRequest = new Request( + [ + 'foo' => '1', + 'bar' => ['baz' => '42'], + ], + [ + 'twitter' => [ + '@dunglas' => 'Kévin Dunglas', + '@coopTilleuls' => 'Les-Tilleuls.coop', + ], + 'baz' => '2', + ], + [ + 'a2' => ['foo' => 'bar'], + ], + [ + 'c1' => 'foo', + 'c2' => ['c3' => 'bar'], + ], + [ + 'f1' => $this->createUploadedFile('F1', 'f1.txt', 'text/plain', UPLOAD_ERR_OK), + 'foo' => ['f2' => $this->createUploadedFile('F2', 'f2.txt', 'text/plain', UPLOAD_ERR_OK)], + ], + [ + 'REQUEST_METHOD' => 'POST', + 'HTTP_HOST' => 'dunglas.fr', + 'SERVER_NAME' => 'dunglas.fr', + 'SERVER_PORT' => null, + 'HTTP_X_SYMFONY' => '2.8', + 'REQUEST_URI' => '/testCreateRequest?bar[baz]=42&foo=1', + 'QUERY_STRING' => 'foo=1&bar[baz]=42', + ], + 'Content' + ); + + $psr7Request = (new Psr7Request('POST', 'http://tnyholm.se/foo/?bar=biz')) + ->withQueryParams(['bar' => 'biz']); + + $nyholmFactory = new Psr17Factory(); + $psr17Factory = new PsrHttpFactory($nyholmFactory, $nyholmFactory, $nyholmFactory, $nyholmFactory); + $symfonyFactory = new HttpFoundationFactory(); + + return [ + [$sfRequest, $psr17Factory, $symfonyFactory], + [$psr7Request, $symfonyFactory, $psr17Factory], + ]; + } + + /** + * @dataProvider responseProvider + * + * @param Response|ResponseInterface $response + * @param HttpFoundationFactoryInterface|HttpMessageFactoryInterface $firstFactory + * @param HttpFoundationFactoryInterface|HttpMessageFactoryInterface $secondFactory + */ + public function testConvertResponseMultipleTimes($response, $firstFactory, $secondFactory) + { + $temporaryResponse = $firstFactory->createResponse($response); + $finalResponse = $secondFactory->createResponse($temporaryResponse); + + if ($finalResponse instanceof Response) { + $this->assertEquals($response->getAge(), $finalResponse->getAge()); + $this->assertEquals($response->getCharset(), $finalResponse->getCharset()); + $this->assertEquals($response->getContent(), $finalResponse->getContent()); + $this->assertEquals($response->getDate(), $finalResponse->getDate()); + $this->assertEquals($response->getEtag(), $finalResponse->getEtag()); + $this->assertEquals($response->getExpires(), $finalResponse->getExpires()); + $this->assertEquals($response->getLastModified(), $finalResponse->getLastModified()); + $this->assertEquals($response->getMaxAge(), $finalResponse->getMaxAge()); + $this->assertEquals($response->getProtocolVersion(), $finalResponse->getProtocolVersion()); + $this->assertEquals($response->getStatusCode(), $finalResponse->getStatusCode()); + $this->assertEquals($response->getTtl(), $finalResponse->getTtl()); + } elseif ($finalResponse instanceof ResponseInterface) { + $strToLower = function ($arr) { + foreach ($arr as $key => $value) { + yield strtolower($key) => $value; + } + }; + $this->assertEquals($response->getStatusCode(), $finalResponse->getStatusCode()); + $this->assertEquals($response->getReasonPhrase(), $finalResponse->getReasonPhrase()); + $this->assertEquals((string) $response->getBody(), (string) $finalResponse->getBody()); + $this->assertEquals($strToLower($response->getHeaders()), $strToLower($finalResponse->getHeaders())); + $this->assertEquals($response->getProtocolVersion(), $finalResponse->getProtocolVersion()); + } else { + $this->fail('$finalResponse must be an instance of PSR7 or a HTTPFoundation response'); + } + } + + public function responseProvider() + { + $sfResponse = new Response( + 'Response content.', + 202, + ['x-symfony' => ['3.4']] + ); + + if (method_exists(Cookie::class, 'create')) { + $cookie = Cookie::create('city', 'Lille', new \DateTime('Wed, 13 Jan 2021 22:23:01 GMT')); + } else { + $cookie = new Cookie('city', 'Lille', new \DateTime('Wed, 13 Jan 2021 22:23:01 GMT')); + } + + $sfResponse->headers->setCookie($cookie); + $body = Psr7Stream::create(); + $status = 302; + $headers = [ + 'location' => ['http://example.com/'], + ]; + $zendResponse = new Psr7Response($status, $headers, $body); + + $nyholmFactory = new Psr17Factory(); + $psr17Factory = new PsrHttpFactory($nyholmFactory, $nyholmFactory, $nyholmFactory, $nyholmFactory); + $symfonyFactory = new HttpFoundationFactory(); + + return [ + [$sfResponse, $psr17Factory, $symfonyFactory], + [$zendResponse, $symfonyFactory, $psr17Factory], + ]; + } + + private function createUploadedFile($content, $originalName, $mimeType, $error) + { + $path = tempnam($this->tmpDir, uniqid()); + file_put_contents($path, $content); + + return new UploadedFile($path, $originalName, $mimeType, $error, true); + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/composer.json b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/composer.json new file mode 100644 index 00000000..07ed9cfe --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/composer.json @@ -0,0 +1,42 @@ +{ + "name": "symfony/psr-http-message-bridge", + "type": "symfony-bridge", + "description": "PSR HTTP message bridge", + "keywords": ["http", "psr-7", "psr-17", "http-message"], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1", + "psr/http-message": "^1.0", + "symfony/http-foundation": "^4.4 || ^5.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.0", + "nyholm/psr7": "^1.1", + "zendframework/zend-diactoros": "^1.4.1 || ^2.0" + }, + "suggest": { + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" + }, + "autoload": { + "psr-4": { "Symfony\\Bridge\\PsrHttpMessage\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/phpunit.xml.dist b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/phpunit.xml.dist new file mode 100644 index 00000000..43aeaa33 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/psr-http-message-bridge/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/lam/lib/webauthn.inc b/lam/lib/webauthn.inc index 4bbd51f2..8dd67fec 100644 --- a/lam/lib/webauthn.inc +++ b/lam/lib/webauthn.inc @@ -15,6 +15,9 @@ use Cose\Algorithm\Signature\RSA\RS256; use Cose\Algorithm\Signature\RSA\RS384; use Cose\Algorithm\Signature\RSA\RS512; use \Cose\Algorithms; +use Nyholm\Psr7\Factory\Psr17Factory; +use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory; +use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; use Symfony\Component\HttpFoundation\Request; use Webauthn\AttestationStatement\AndroidKeyAttestationStatementSupport; use Webauthn\AttestationStatement\AttestationObjectLoader; @@ -64,6 +67,8 @@ use Webauthn\TokenBinding\IgnoreTokenBindingHandler; * @author Roland Gruber */ +include_once __DIR__ . '/3rdParty/composer/autoload.php'; + /** * Returns if the given DN is registered for webauthn. * @@ -165,7 +170,6 @@ function storeNewRegistration($registration, $clientResponse) { $responseValidator = new AuthenticatorAttestationResponseValidator( $attestationSupportManager, $repository, $tokenBindingHandler, $extensionOutputCheckerHandler); try { - logNewMessage(LOG_ERR, 'RESPONSE: ' . $clientResponse); $publicKeyCredential = $publicKeyCredentialLoader->load($clientResponse); $authenticatorAttestationResponse = $publicKeyCredential->getResponse(); if (!$authenticatorAttestationResponse instanceof AuthenticatorAttestationResponse) { @@ -173,7 +177,11 @@ function storeNewRegistration($registration, $clientResponse) { return false; } $symfonyRequest = Request::createFromGlobals(); - $responseValidator->check($authenticatorAttestationResponse, $registration, $symfonyRequest); + $psr17Factory = new Psr17Factory(); + $psrFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory); + $psr7Request = $psrFactory->createRequest($symfonyRequest); + $publicKeyCredentialSource = $responseValidator->check($authenticatorAttestationResponse, $registration, $psr7Request); + $repository->saveCredentialSource($publicKeyCredentialSource); return true; } catch (\Throwable $exception) { diff --git a/lam/templates/lib/500_lam.js b/lam/templates/lib/500_lam.js index 32ae92d4..cd2b850b 100644 --- a/lam/templates/lib/500_lam.js +++ b/lam/templates/lib/500_lam.js @@ -1395,7 +1395,6 @@ window.lam.webauthn.run = function(prefix) { data: data }) .done(function(jsonData) { - console.log(jsonData); if (jsonData.action === 'register') { window.lam.webauthn.register(jsonData.registration); } diff --git a/lam/templates/misc/ajax.php b/lam/templates/misc/ajax.php index 4634518e..2db6062c 100644 --- a/lam/templates/misc/ajax.php +++ b/lam/templates/misc/ajax.php @@ -191,13 +191,12 @@ class Ajax { * @param bool $isSelfService request is from self service */ private function manageWebauthn($isSelfService) { - include_once __DIR__ . '/../../lib/3rdParty/composer/autoload.php'; include_once __DIR__ . '/../../lib/webauthn.inc'; $userDN = $_SESSION['ldap']->getUserName(); $isRegistered = isRegistered($userDN); if (!$isRegistered) { $registrationObject = getRegistrationObject($userDN, $isSelfService); - $_SESSION['webauthn_registration'] = $registrationObject; + $_SESSION['webauthn_registration'] = json_encode($registrationObject); echo json_encode( array( 'action' => 'register',