diff --git a/.github/workflows/ci-php.yaml b/.github/workflows/ci-php.yaml index b99b1bdd..07f85fde 100644 --- a/.github/workflows/ci-php.yaml +++ b/.github/workflows/ci-php.yaml @@ -3,6 +3,7 @@ on: push: branches: - main + - phpdev-* paths: - "php/**" - ".github/workflows/ci-php.yaml" @@ -129,8 +130,14 @@ jobs: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/php}" >> $GITHUB_ENV echo $RELEASE_VERSION + - name: extract version + if: startsWith(github.ref, 'refs/heads/phpdev-') + run: | + echo "RELEASE_VERSION=${GITHUB_REF#refs/*/phpdev-}" >> $GITHUB_ENV + echo $RELEASE_VERSION + - name: checkout - if: startsWith(github.ref, 'refs/tags/php') + if: startsWith(github.ref, 'refs/tags/php') || startsWith(github.ref, 'refs/heads/phpdev-') uses: actions/checkout@v4 - name: publish on site repo @@ -151,8 +158,25 @@ jobs: git remote add origin https://ata-no-one:$GITHUB_TOKEN@github.com/GDATASoftwareAG/vaas-php git push origin main --tags --force + - name: publish on site repo + if: startsWith(github.ref, 'refs/heads/phpdev-') + env: + GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} + working-directory: php/src/vaas + run: | + git config --global user.email "ata-no-one@gdata.de" + git config --global user.name "Version Bot" + sed -i "s/\"version\": \"[0-9]\+\.[0-9]\+\.[0-9]\+\"/\"version\": \"$RELEASE_VERSION\"/g" ./composer.json + cp ../../../Readme.md . + git init + git add . + git commit -m"publish php $RELEASE_VERSION" + git branch -M $RELEASE_VERSION + git remote add origin https://ata-no-one:$GITHUB_TOKEN@github.com/GDATASoftwareAG/vaas-php + git push origin $RELEASE_VERSION --force + - name: sync packagist - if: startsWith(github.ref, 'refs/tags/php') + if: startsWith(github.ref, 'refs/tags/php') || startsWith(github.ref, 'refs/heads/phpdev-') env: PACKAGIST_API_TOKEN: ${{ secrets.PACKAGIST_API_TOKEN }} run: curl -XPOST -H'content-type:application/json' "https://packagist.org/api/update-package?username=gdatacyberdefense&apiToken=$PACKAGIST_API_TOKEN" -d'{"repository":{"url":"https://packagist.org/packages/gdata/vaas"}}' diff --git a/php/composer-update.sh b/php/composer-update.sh new file mode 100644 index 00000000..ce81d042 --- /dev/null +++ b/php/composer-update.sh @@ -0,0 +1,5 @@ +find . -name composer.json -not -path */vendor/* | while read composer; do + dir=$(dirname $composer) + echo "Updating $dir" + composer --working-dir=$dir update +done \ No newline at end of file diff --git a/php/examples/VaasExample/GetVerdictByFile.php b/php/examples/VaasExample/GetVerdictByFile.php index df7de9cf..47782e24 100644 --- a/php/examples/VaasExample/GetVerdictByFile.php +++ b/php/examples/VaasExample/GetVerdictByFile.php @@ -13,11 +13,11 @@ getenv("TOKEN_URL") ?: "https://account.gdata.de/realms/vaas-production/protocol/openid-connect/token" ); -$vaas = new Vaas( - getenv("VAAS_URL") ?? "wss://gateway.production.vaas.gdatasecurity.de" -); +$vaas = (new Vaas()) + ->withAuthenticator($authenticator) + ->withUrl(getenv("VAAS_URL") ?? "wss://gateway.production.vaas.gdatasecurity.de") + ->build(); -$vaas->Connect($authenticator->getToken()); $scanPath = getenv("SCAN_PATH"); $vaasVerdict = $vaas->ForFile($scanPath); diff --git a/php/examples/VaasExample/GetVerdictByHash.php b/php/examples/VaasExample/GetVerdictByHash.php index 287bd325..097de49f 100644 --- a/php/examples/VaasExample/GetVerdictByHash.php +++ b/php/examples/VaasExample/GetVerdictByHash.php @@ -12,10 +12,10 @@ getenv("CLIENT_SECRET"), getenv("TOKEN_URL") ?: "https://account.gdata.de/realms/vaas-production/protocol/openid-connect/token" ); -$vaas = new Vaas( - getenv("VAAS_URL") ?: "wss://gateway.production.vaas.gdatasecurity.de" -); -$vaas->Connect($authenticator->getToken()); +$vaas = (new Vaas()) + ->withAuthenticator($authenticator) + ->withUrl(getenv("VAAS_URL") ?? "wss://gateway.production.vaas.gdatasecurity.de") + ->build(); // EICAR $vaasVerdict = $vaas->ForSha256("000005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8"); diff --git a/php/examples/VaasExample/GetVerdictByUrl.php b/php/examples/VaasExample/GetVerdictByUrl.php index 529436cc..70757bf7 100644 --- a/php/examples/VaasExample/GetVerdictByUrl.php +++ b/php/examples/VaasExample/GetVerdictByUrl.php @@ -12,10 +12,10 @@ getenv("CLIENT_SECRET"), getenv("TOKEN_URL") ?: "https://account.gdata.de/realms/vaas-production/protocol/openid-connect/token" ); -$vaas = new Vaas( - getenv("VAAS_URL") ?: "wss://gateway.production.vaas.gdatasecurity.de" -); -$vaas->Connect($authenticator->getToken()); +$vaas = (new Vaas()) + ->withAuthenticator($authenticator) + ->withUrl(getenv("VAAS_URL") ?? "wss://gateway.production.vaas.gdatasecurity.de") + ->build(); // EICAR $vaasVerdict = $vaas->ForUrl("https://secure.eicar.org/eicar.com"); diff --git a/php/examples/wordpress/src/gd-scan/Vaas/Client.php b/php/examples/wordpress/src/gd-scan/Vaas/Client.php index 24745b04..7266a3d5 100644 --- a/php/examples/wordpress/src/gd-scan/Vaas/Client.php +++ b/php/examples/wordpress/src/gd-scan/Vaas/Client.php @@ -2,14 +2,32 @@ namespace WpGdScan\Vaas; +use VaasSdk\Vaas; +use VaasSdk\Authentication\ClientCredentialsGrantAuthenticator; + class Client { + private Vaas $vaas; + + public function __construct() + { + $authenticator = new ClientCredentialsGrantAuthenticator( + getenv("CLIENT_ID"), + getenv("CLIENT_SECRET"), + getenv("TOKEN_URL") ?: "https://account.gdata.de/realms/vaas-production/protocol/openid-connect/token" + ); + $this->vaas = (new Vaas()) + ->withAuthenticator($authenticator) + ->build(); + } + public function scanSingleFile(string $fileName): void { file_put_contents(\plugin_dir_path(__FILE__) . "/log", "Filename: $fileName\n", FILE_APPEND); file_put_contents(\plugin_dir_path(__FILE__) . "/log", "Try to get Verdict: $fileName\n", FILE_APPEND); - if ((new \VaasSdk\Vaas("Token"))->ForFile($fileName) == \VaasSdk\Message\Verdict::MALICIOUS) { + + if ($this->vaas->ForFile($fileName) == \VaasSdk\Message\Verdict::MALICIOUS) { file_put_contents( \plugin_dir_path(__FILE__) . "/log", \VaasSdk\Message\Verdict::MALICIOUS . ": $fileName\n", diff --git a/php/examples/wordpress/src/gd-scan/composer.lock b/php/examples/wordpress/src/gd-scan/composer.lock index 9a75771f..9fdbcac8 100644 --- a/php/examples/wordpress/src/gd-scan/composer.lock +++ b/php/examples/wordpress/src/gd-scan/composer.lock @@ -6,27 +6,1369 @@ ], "content-hash": "f02954eb7b498339267607d24ab420b9", "packages": [ + { + "name": "amphp/amp", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "138801fb68cfc9c329da8a7b39d01ce7291ee4b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/138801fb68cfc9c329da8a7b39d01ce7291ee4b0", + "reference": "138801fb68cfc9c329da8a7b39d01ce7291ee4b0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Future/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "https://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/v3.0.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-05-10T21:37:46+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "daa00f2efdbd71565bf64ffefa89e37542addf93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/daa00f2efdbd71565bf64ffefa89e37542addf93", + "reference": "daa00f2efdbd71565bf64ffefa89e37542addf93", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/parser": "^1.1", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2.3" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.22.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\ByteStream\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "https://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/v2.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-02-17T04:49:38+00:00" + }, + { + "name": "amphp/cache", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/cache.git", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Cache\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A fiber-aware cache API based on Amp and Revolt.", + "homepage": "https://amphp.org/cache", + "support": { + "issues": "https://github.com/amphp/cache/issues", + "source": "https://github.com/amphp/cache/tree/v2.0.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-19T03:38:06+00:00" + }, + { + "name": "amphp/dns", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/dns.git", + "reference": "758266b0ea7470e2e42cd098493bc6d6c7100cf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/dns/zipball/758266b0ea7470e2e42cd098493bc6d6c7100cf7", + "reference": "758266b0ea7470e2e42cd098493bc6d6c7100cf7", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/parser": "^1", + "amphp/windows-registry": "^1.0.1", + "daverandom/libdns": "^2.0.2", + "ext-filter": "*", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.20" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Dns\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Wright", + "email": "addr@daverandom.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Async DNS resolution for Amp.", + "homepage": "https://github.com/amphp/dns", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "dns", + "resolve" + ], + "support": { + "issues": "https://github.com/amphp/dns/issues", + "source": "https://github.com/amphp/dns/tree/v2.2.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-06-02T19:54:12+00:00" + }, + { + "name": "amphp/file", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/file.git", + "reference": "58c8efefb8808d25456ef3ef4a628645442578a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/file/zipball/58c8efefb8808d25456ef3ef4a628645442578a2", + "reference": "58c8efefb8808d25456ef3ef4a628645442578a2", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/parallel": "^2.1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.22.2" + }, + "suggest": { + "ext-eio": "^2 || ^3", + "ext-uv": "^0.3 || ^0.2" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\File\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Non-blocking access to the filesystem based on Amp and Revolt.", + "homepage": "https://github.com/amphp/file", + "keywords": [ + "amp", + "amphp", + "async", + "disk", + "file", + "filesystem", + "io", + "non-blocking", + "static" + ], + "support": { + "issues": "https://github.com/amphp/file/issues", + "source": "https://github.com/amphp/file/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-08-15T15:04:06+00:00" + }, + { + "name": "amphp/hpack", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/hpack.git", + "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/hpack/zipball/4f293064b15682a2b178b1367ddf0b8b5feb0239", + "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "http2jp/hpack-test-case": "^1", + "nikic/php-fuzzer": "^0.0.10", + "phpunit/phpunit": "^7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "HTTP/2 HPack implementation.", + "homepage": "https://github.com/amphp/hpack", + "keywords": [ + "headers", + "hpack", + "http-2" + ], + "support": { + "issues": "https://github.com/amphp/hpack/issues", + "source": "https://github.com/amphp/hpack/tree/v3.2.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-03-21T19:00:16+00:00" + }, + { + "name": "amphp/http", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/http.git", + "reference": "fe6b4dd50c1e70caf823092398074b5082e1d6da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http/zipball/fe6b4dd50c1e70caf823092398074b5082e1d6da", + "reference": "fe6b4dd50c1e70caf823092398074b5082e1d6da", + "shasum": "" + }, + "require": { + "amphp/hpack": "^3", + "amphp/parser": "^1.1", + "league/uri-components": "^2.4.2 | ^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "league/uri": "^6.8 | ^7.1", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/constants.php" + ], + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Basic HTTP primitives which can be shared by servers and clients.", + "support": { + "issues": "https://github.com/amphp/http/issues", + "source": "https://github.com/amphp/http/tree/v2.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-03T18:00:53+00:00" + }, + { + "name": "amphp/http-client", + "version": "v5.1.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-client.git", + "reference": "483df9a856625fe4406c7fb6a64d6787105bd184" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-client/zipball/483df9a856625fe4406c7fb6a64d6787105bd184", + "reference": "483df9a856625fe4406c7fb6a64d6787105bd184", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/hpack": "^3", + "amphp/http": "^2", + "amphp/pipeline": "^1", + "amphp/socket": "^2", + "amphp/sync": "^2", + "league/uri": "^6 | ^7", + "league/uri-components": "^2.4 | ^7", + "league/uri-interfaces": "^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/file": "^3", + "amphp/http-server": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "ext-json": "*", + "kelunik/link-header-rfc5988": "^1", + "laminas/laminas-diactoros": "^2.3", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.23" + }, + "suggest": { + "amphp/file": "Required for file request bodies and HTTP archive logging", + "ext-json": "Required for logging HTTP archives", + "ext-zlib": "Allows using compression for response bodies." + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\Http\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses.", + "homepage": "https://amphp.org/http-client", + "keywords": [ + "async", + "client", + "concurrent", + "http", + "non-blocking", + "rest" + ], + "support": { + "issues": "https://github.com/amphp/http-client/issues", + "source": "https://github.com/amphp/http-client/tree/v5.1.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-21T16:40:36+00:00" + }, + { + "name": "amphp/parallel", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/parallel.git", + "reference": "9777db1460d1535bc2a843840684fb1205225b87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parallel/zipball/9777db1460d1535bc2a843840684fb1205225b87", + "reference": "9777db1460d1535bc2a843840684fb1205225b87", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/parser": "^1", + "amphp/pipeline": "^1", + "amphp/process": "^2", + "amphp/serialization": "^1", + "amphp/socket": "^2", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18" + }, + "type": "library", + "autoload": { + "files": [ + "src/Context/functions.php", + "src/Context/Internal/functions.php", + "src/Ipc/functions.php", + "src/Worker/functions.php" + ], + "psr-4": { + "Amp\\Parallel\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Stephen Coakley", + "email": "me@stephencoakley.com" + } + ], + "description": "Parallel processing component for Amp.", + "homepage": "https://github.com/amphp/parallel", + "keywords": [ + "async", + "asynchronous", + "concurrent", + "multi-processing", + "multi-threading" + ], + "support": { + "issues": "https://github.com/amphp/parallel/issues", + "source": "https://github.com/amphp/parallel/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-09-14T19:16:14+00:00" + }, + { + "name": "amphp/parser", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/parser.git", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Parser\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A generator parser to make streaming parsers simple.", + "homepage": "https://github.com/amphp/parser", + "keywords": [ + "async", + "non-blocking", + "parser", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/parser/issues", + "source": "https://github.com/amphp/parser/tree/v1.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-03-21T19:16:53+00:00" + }, + { + "name": "amphp/pipeline", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/pipeline.git", + "reference": "66c095673aa5b6e689e63b52d19e577459129ab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/pipeline/zipball/66c095673aa5b6e689e63b52d19e577459129ab3", + "reference": "66c095673aa5b6e689e63b52d19e577459129ab3", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Pipeline\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Asynchronous iterators and operators.", + "homepage": "https://amphp.org/pipeline", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "iterator", + "non-blocking" + ], + "support": { + "issues": "https://github.com/amphp/pipeline/issues", + "source": "https://github.com/amphp/pipeline/tree/v1.2.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-07-04T00:56:47+00:00" + }, + { + "name": "amphp/process", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/process.git", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Process\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A fiber-aware process manager based on Amp and Revolt.", + "homepage": "https://amphp.org/process", + "support": { + "issues": "https://github.com/amphp/process/issues", + "source": "https://github.com/amphp/process/tree/v2.0.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-19T03:13:44+00:00" + }, + { + "name": "amphp/serialization", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/serialization.git", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "phpunit/phpunit": "^9 || ^8 || ^7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Serialization\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Serialization tools for IPC and data storage in PHP.", + "homepage": "https://github.com/amphp/serialization", + "keywords": [ + "async", + "asynchronous", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/amphp/serialization/issues", + "source": "https://github.com/amphp/serialization/tree/master" + }, + "time": "2020-03-25T21:39:07+00:00" + }, + { + "name": "amphp/socket", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/socket.git", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/dns": "^2", + "ext-openssl": "*", + "kelunik/certificate": "^1.1", + "league/uri": "^6.5 | ^7", + "league/uri-interfaces": "^2.3 | ^7", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/process": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.20" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php", + "src/SocketAddress/functions.php" + ], + "psr-4": { + "Amp\\Socket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.", + "homepage": "https://github.com/amphp/socket", + "keywords": [ + "amp", + "async", + "encryption", + "non-blocking", + "sockets", + "tcp", + "tls" + ], + "support": { + "issues": "https://github.com/amphp/socket/issues", + "source": "https://github.com/amphp/socket/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-21T14:33:03+00:00" + }, + { + "name": "amphp/sync", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/sync.git", + "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1", + "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Sync\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Stephen Coakley", + "email": "me@stephencoakley.com" + } + ], + "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.", + "homepage": "https://github.com/amphp/sync", + "keywords": [ + "async", + "asynchronous", + "mutex", + "semaphore", + "synchronization" + ], + "support": { + "issues": "https://github.com/amphp/sync/issues", + "source": "https://github.com/amphp/sync/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-08-03T19:31:26+00:00" + }, + { + "name": "amphp/websocket", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/websocket.git", + "reference": "1dc9d2c3b9b10965510d2762181254d825098419" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/websocket/zipball/1dc9d2c3b9b10965510d2762181254d825098419", + "reference": "1dc9d2c3b9b10965510d2762181254d825098419", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/parser": "^1", + "amphp/pipeline": "^1", + "amphp/socket": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18" + }, + "suggest": { + "ext-zlib": "Required for compression" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Websocket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + } + ], + "description": "Shared code for websocket servers and clients.", + "homepage": "https://github.com/amphp/websocket", + "keywords": [ + "amp", + "amphp", + "async", + "http", + "non-blocking", + "websocket" + ], + "support": { + "issues": "https://github.com/amphp/websocket/issues", + "source": "https://github.com/amphp/websocket/tree/v2.0.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2023-12-28T23:16:28+00:00" + }, + { + "name": "amphp/websocket-client", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/websocket-client.git", + "reference": "87a5d324997421c79cafbacb9a0f870f95fd42e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/websocket-client/zipball/87a5d324997421c79cafbacb9a0f870f95fd42e9", + "reference": "87a5d324997421c79cafbacb9a0f870f95fd42e9", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2.1", + "amphp/http": "^2.1", + "amphp/http-client": "^5", + "amphp/socket": "^2.2", + "amphp/websocket": "^2", + "league/uri": "^6.8|^7.1", + "php": ">=8.1", + "psr/http-message": "^1|^2", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/http-server": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/websocket-server": "^3|^4", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18", + "psr/log": "^1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Websocket\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Async WebSocket client for PHP based on Amp.", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "http", + "non-blocking", + "websocket" + ], + "support": { + "issues": "https://github.com/amphp/websocket-client/issues", + "source": "https://github.com/amphp/websocket-client/tree/v2.0.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2023-12-28T01:48:55+00:00" + }, + { + "name": "amphp/windows-registry", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/windows-registry.git", + "reference": "0d569e8f256cca974e3842b6e78b4e434bf98306" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/windows-registry/zipball/0d569e8f256cca974e3842b6e78b4e434bf98306", + "reference": "0d569e8f256cca974e3842b6e78b4e434bf98306", + "shasum": "" + }, + "require": { + "amphp/byte-stream": "^2", + "amphp/process": "^2", + "php": ">=8.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\WindowsRegistry\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Windows Registry Reader.", + "support": { + "issues": "https://github.com/amphp/windows-registry/issues", + "source": "https://github.com/amphp/windows-registry/tree/v1.0.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-01-30T23:01:51+00:00" + }, { "name": "brick/math", - "version": "0.11.0", + "version": "0.12.1", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" + "reference": "f510c0a40911935b77b86859eb5223d58d660df1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", - "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", + "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1", + "reference": "f510c0a40911935b77b86859eb5223d58d660df1", "shasum": "" }, "require": { - "php": "^8.0" + "php": "^8.1" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^9.0", - "vimeo/psalm": "5.0.0" + "phpunit/phpunit": "^10.1", + "vimeo/psalm": "5.16.0" }, "type": "library", "autoload": { @@ -46,12 +1388,17 @@ "arithmetic", "bigdecimal", "bignum", + "bignumber", "brick", - "math" + "decimal", + "integer", + "math", + "mathematics", + "rational" ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.11.0" + "source": "https://github.com/brick/math/tree/0.12.1" }, "funding": [ { @@ -59,7 +1406,51 @@ "type": "github" } ], - "time": "2023-01-15T23:15:59+00:00" + "time": "2023-11-29T23:19:16+00:00" + }, + { + "name": "daverandom/libdns", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/DaveRandom/LibDNS.git", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "Required for IDN support" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "LibDNS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "DNS protocol implementation written in pure PHP", + "keywords": [ + "dns" + ], + "support": { + "issues": "https://github.com/DaveRandom/LibDNS/issues", + "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0" + }, + "time": "2024-04-12T12:12:48+00:00" }, { "name": "gdata/vaas", @@ -67,14 +1458,18 @@ "dist": { "type": "path", "url": "../../../../src/vaas", - "reference": "194deb5350ed40bde6f455258b641c84825b4ebf" + "reference": "3092a4236d4d84708c8da75e5fa505150eaf4635" }, "require": { - "guzzlehttp/guzzle": "^7", - "netresearch/jsonmapper": "^4.1", + "amphp/amp": "3.0.2", + "amphp/cache": "2.0.1", + "amphp/file": "3.1.1", + "amphp/http-client": "5.1.0", + "amphp/websocket-client": "2.0.0", + "netresearch/jsonmapper": "^5.0", + "php": "^8.1", "psr/log": "^1.1 || ^2.0 || ^3.0", - "ramsey/uuid": "^4.6", - "textalk/websocket": "^1.6" + "ramsey/uuid": "^4.7 || ^4.2" }, "type": "library", "autoload": { @@ -85,70 +1480,117 @@ "license": [ "MIT" ], - "description": "Verdict-as-a-Service (VaaS) is a service that provides a platform for scanning files for malware and other threats. It allows easy integration in your application. With a few lines of code, you can start scanning files for malware.", - "homepage": "https://github.com/GDATASoftwareAG/vaas", + "description": "Verdict-as-a-Service (VaaS) is a service that provides a platform for scanning files for malware and other threats. It allows easy integration in your application. With a few lines of code, you can start scanning files for malware.", + "homepage": "https://github.com/GDATASoftwareAG/vaas", + "keywords": [ + "antivirus", + "malware", + "security", + "virusscan" + ], + "transport-options": { + "symlink": false, + "relative": true + } + }, + { + "name": "kelunik/certificate", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/kelunik/certificate.git", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=7.0" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Kelunik\\Certificate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Access certificate details and transform between different formats.", "keywords": [ - "antivirus", - "malware", - "security", - "virusscan" + "DER", + "certificate", + "certificates", + "openssl", + "pem", + "x509" ], - "transport-options": { - "symlink": false, - "relative": true - } + "support": { + "issues": "https://github.com/kelunik/certificate/issues", + "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + }, + "time": "2023-02-03T21:26:53+00:00" }, { - "name": "guzzlehttp/guzzle", - "version": "7.7.0", + "name": "league/uri", + "version": "7.4.1", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5" + "url": "https://github.com/thephpleague/uri.git", + "reference": "bedb6e55eff0c933668addaa7efa1e1f2c417cc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5", - "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/bedb6e55eff0c933668addaa7efa1e1f2c417cc4", + "reference": "bedb6e55eff0c933668addaa7efa1e1f2c417cc4", "shasum": "" }, "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0", - "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", - "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0" - }, - "provide": { - "psr/http-client-implementation": "1.0" + "league/uri-interfaces": "^7.3", + "php": "^8.1" }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "ext-curl": "*", - "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", - "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23", - "psr/log": "^1.1 || ^2.0 || ^3.0" + "conflict": { + "league/uri-schemes": "^1.0" }, "suggest": { - "ext-curl": "Required for CURL handler support", - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "league/uri-components": "Needed to easily manipulate URI objects components", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false + "branch-alias": { + "dev-master": "7.x-dev" } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { - "GuzzleHttp\\": "src/" + "League\\Uri\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -157,104 +1599,85 @@ ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Jeremy Lindblom", - "email": "jeremeamia@gmail.com", - "homepage": "https://github.com/jeremeamia" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" } ], - "description": "Guzzle is a PHP HTTP client library", + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", "keywords": [ - "client", - "curl", - "framework", + "data-uri", + "file-uri", + "ftp", + "hostname", "http", - "http client", - "psr-18", + "https", + "middleware", + "parse_str", + "parse_url", "psr-7", - "rest", - "web service" + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" ], "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.7.0" + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.4.1" }, "funding": [ { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", + "url": "https://github.com/sponsors/nyamsprod", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", - "type": "tidelift" } ], - "time": "2023-05-21T14:04:53+00:00" + "time": "2024-03-23T07:42:40+00:00" }, { - "name": "guzzlehttp/promises", - "version": "2.0.0", + "name": "league/uri-components", + "version": "7.4.1", "source": { "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6" + "url": "https://github.com/thephpleague/uri-components.git", + "reference": "b94fe4097885f1b51c4c3fcb78025fbbabbb5d9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6", - "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6", + "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/b94fe4097885f1b51c4c3fcb78025fbbabbb5d9d", + "reference": "b94fe4097885f1b51c4c3fcb78025fbbabbb5d9d", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0" + "league/uri": "^7.3", + "php": "^8.1" }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "ext-mbstring": "to use the sorting algorithm of URLSearchParams", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false + "branch-alias": { + "dev-master": "7.x-dev" } }, "autoload": { "psr-4": { - "GuzzleHttp\\Promise\\": "src/" + "League\\Uri\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -263,92 +1686,79 @@ ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" } ], - "description": "Guzzle promises library", + "description": "URI components manipulation library", + "homepage": "http://uri.thephpleague.com", "keywords": [ - "promise" + "authority", + "components", + "fragment", + "host", + "middleware", + "modifier", + "path", + "port", + "query", + "rfc3986", + "scheme", + "uri", + "url", + "userinfo" ], "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.0" + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-components/tree/7.4.1" }, "funding": [ { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", + "url": "https://github.com/nyamsprod", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", - "type": "tidelift" } ], - "time": "2023-05-21T13:50:22+00:00" + "time": "2024-03-23T07:42:40+00:00" }, { - "name": "guzzlehttp/psr7", - "version": "2.5.0", + "name": "league/uri-interfaces", + "version": "7.4.1", "source": { "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6" + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "8d43ef5c841032c87e2de015972c06f3865ef718" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/8d43ef5c841032c87e2de015972c06f3865ef718", + "reference": "8d43ef5c841032c87e2de015972c06f3865ef718", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "ext-filter": "*", + "php": "^8.1", + "psr/http-factory": "^1", + "psr/http-message": "^1.1 || ^2.0" }, "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false + "branch-alias": { + "dev-master": "7.x-dev" } }, "autoload": { "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" + "League\\Uri\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -357,84 +1767,58 @@ ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" } ], - "description": "PSR-7 message implementation that also provides common utility methods", + "description": "Common interfaces and classes for URI representation and interaction", + "homepage": "https://uri.thephpleague.com", "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", "http", - "message", + "https", + "parse_str", + "parse_url", "psr-7", - "request", - "response", - "stream", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", "uri", - "url" + "url", + "ws" ], "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.5.0" + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.4.1" }, "funding": [ { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", + "url": "https://github.com/sponsors/nyamsprod", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" } ], - "time": "2023-04-17T16:11:26+00:00" + "time": "2024-03-23T07:42:40+00:00" }, { "name": "netresearch/jsonmapper", - "version": "v4.2.0", + "version": "v5.0.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" + "reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c", + "reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c", "shasum": "" }, "require": { @@ -445,7 +1829,7 @@ "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", "squizlabs/php_codesniffer": "~3.5" }, "type": "library", @@ -470,184 +1854,26 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" - }, - "time": "2023-04-09T17:37:40+00:00" - }, - { - "name": "phrity/net-uri", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/sirn-se/phrity-net-uri.git", - "reference": "c6ecf127e7c99a41ce04d3cdcda7f51108dd96f7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sirn-se/phrity-net-uri/zipball/c6ecf127e7c99a41ce04d3cdcda7f51108dd96f7", - "reference": "c6ecf127e7c99a41ce04d3cdcda7f51108dd96f7", - "shasum": "" - }, - "require": { - "php": "^7.4|^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.0", - "phpunit/phpunit": "^9.0", - "squizlabs/php_codesniffer": "^3.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Sören Jensen", - "email": "sirn@sirn.se", - "homepage": "https://phrity.sirn.se" - } - ], - "description": "PSR-7 Uri and PSR-17 UriFactory implementation", - "homepage": "https://phrity.sirn.se/net-uri", - "keywords": [ - "psr-17", - "psr-7", - "uri", - "uri factory" - ], - "support": { - "issues": "https://github.com/sirn-se/phrity-net-uri/issues", - "source": "https://github.com/sirn-se/phrity-net-uri/tree/1.2.0" - }, - "time": "2022-11-30T07:20:06+00:00" - }, - { - "name": "phrity/util-errorhandler", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sirn-se/phrity-util-errorhandler.git", - "reference": "dc9ac8fb70d733c48a9d9d1eb50f7022172da6bc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sirn-se/phrity-util-errorhandler/zipball/dc9ac8fb70d733c48a9d9d1eb50f7022172da6bc", - "reference": "dc9ac8fb70d733c48a9d9d1eb50f7022172da6bc", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v5.0.0" }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.0", - "phpunit/phpunit": "^8.0|^9.0", - "squizlabs/php_codesniffer": "^3.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Sören Jensen", - "email": "sirn@sirn.se", - "homepage": "https://phrity.sirn.se" - } - ], - "description": "Inline error handler; catch and resolve errors for code block.", - "homepage": "https://phrity.sirn.se/util-errorhandler", - "keywords": [ - "error", - "warning" - ], - "support": { - "issues": "https://github.com/sirn-se/phrity-util-errorhandler/issues", - "source": "https://github.com/sirn-se/phrity-util-errorhandler/tree/1.0.1" - }, - "time": "2022-10-27T12:14:42+00:00" - }, - { - "name": "psr/http-client", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", - "shasum": "" - }, - "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], - "support": { - "source": "https://github.com/php-fig/http-client/tree/1.0.2" - }, - "time": "2023-04-10T20:12:12+00:00" + "time": "2024-09-08T10:20:00+00:00" }, { "name": "psr/http-factory", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -671,7 +1897,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -683,22 +1909,22 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", - "version": "1.1", + "version": "2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { @@ -707,7 +1933,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -722,7 +1948,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -736,22 +1962,22 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/1.1" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2023-04-04T09:50:52+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -786,53 +2012,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" - }, - "time": "2021-07-14T16:46:02+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2019-03-08T08:55:37+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "ramsey/collection", @@ -925,20 +2107,20 @@ }, { "name": "ramsey/uuid", - "version": "4.7.4", + "version": "4.7.6", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "60a4c63ab724854332900504274f6150ff26d286" + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/60a4c63ab724854332900504274f6150ff26d286", - "reference": "60a4c63ab724854332900504274f6150ff26d286", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", "ext-json": "*", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" @@ -1001,7 +2183,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.7.4" + "source": "https://github.com/ramsey/uuid/tree/4.7.6" }, "funding": [ { @@ -1013,39 +2195,41 @@ "type": "tidelift" } ], - "time": "2023-04-15T23:01:58+00:00" + "time": "2024-04-27T21:32:50+00:00" }, { - "name": "symfony/deprecation-contracts", - "version": "v3.2.1", + "name": "revolt/event-loop", + "version": "v1.0.6", "source": { "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e" + "url": "https://github.com/revoltphp/event-loop.git", + "reference": "25de49af7223ba039f64da4ae9a28ec2d10d0254" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/25de49af7223ba039f64da4ae9a28ec2d10d0254", + "reference": "25de49af7223ba039f64da4ae9a28ec2d10d0254", "shasum": "" }, "require": { "php": ">=8.1" }, + "require-dev": { + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.15" + }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "dev-main": "1.x-dev" } }, "autoload": { - "files": [ - "function.php" - ] + "psr-4": { + "Revolt\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1053,85 +2237,37 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com" }, { - "url": "https://github.com/fabpot", - "type": "github" + "name": "Christian Lück", + "email": "christian@clue.engineering" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-03-01T10:25:55+00:00" - }, - { - "name": "textalk/websocket", - "version": "1.6.3", - "source": { - "type": "git", - "url": "https://github.com/Textalk/websocket-php.git", - "reference": "67de79745b1a357caf812bfc44e0abf481cee012" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Textalk/websocket-php/zipball/67de79745b1a357caf812bfc44e0abf481cee012", - "reference": "67de79745b1a357caf812bfc44e0abf481cee012", - "shasum": "" - }, - "require": { - "php": "^7.4 | ^8.0", - "phrity/net-uri": "^1.0", - "phrity/util-errorhandler": "^1.0", - "psr/http-message": "^1.0", - "psr/log": "^1.0 | ^2.0 | ^3.0" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.0", - "phpunit/phpunit": "^9.0", - "squizlabs/php_codesniffer": "^3.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "WebSocket\\": "lib" + "name": "Niklas Keller", + "email": "me@kelunik.com" } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" ], - "authors": [ - { - "name": "Fredrik Liljegren" - }, - { - "name": "Sören Jensen" - } + "description": "Rock-solid event loop for concurrent PHP applications.", + "keywords": [ + "async", + "asynchronous", + "concurrency", + "event", + "event-loop", + "non-blocking", + "scheduler" ], - "description": "WebSocket client and server", "support": { - "issues": "https://github.com/Textalk/websocket-php/issues", - "source": "https://github.com/Textalk/websocket-php/tree/1.6.3" + "issues": "https://github.com/revoltphp/event-loop/issues", + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.6" }, - "time": "2022-11-07T18:59:33+00:00" + "time": "2023-11-30T05:34:44+00:00" } ], "packages-dev": [], @@ -1144,5 +2280,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/php/src/vaas/Authentication/AuthenticatorInterface.php b/php/src/vaas/Authentication/AuthenticatorInterface.php new file mode 100644 index 00000000..405def57 --- /dev/null +++ b/php/src/vaas/Authentication/AuthenticatorInterface.php @@ -0,0 +1,7 @@ +_tokenReceiver = new OAuth2TokenReceiver($tokenEndpoint, $clientId, $clientSecret); } - public function getToken(): string - { + public function getToken(): string { return $this->_tokenReceiver->GetToken(); } } diff --git a/php/src/vaas/Authentication/OAuth2TokenReceiver.php b/php/src/vaas/Authentication/OAuth2TokenReceiver.php index de137670..2c48ba55 100644 --- a/php/src/vaas/Authentication/OAuth2TokenReceiver.php +++ b/php/src/vaas/Authentication/OAuth2TokenReceiver.php @@ -50,7 +50,7 @@ public function __construct( } } - public function getToken() { + public function getToken(): string { try { $request = new Request($this->_tokenEndpoint, 'POST'); $request->addHeader('Content-Type', 'application/x-www-form-urlencoded'); diff --git a/php/src/vaas/Authentication/ResourceOwnerPasswordGrantAuthenticator.php b/php/src/vaas/Authentication/ResourceOwnerPasswordGrantAuthenticator.php index 321e19c7..88728818 100644 --- a/php/src/vaas/Authentication/ResourceOwnerPasswordGrantAuthenticator.php +++ b/php/src/vaas/Authentication/ResourceOwnerPasswordGrantAuthenticator.php @@ -5,7 +5,7 @@ use VaasSdk\Authentication\OAuth2TokenReceiver; use VaasSdk\Exceptions\VaasAuthenticationException; -class ResourceOwnerPasswordGrantAuthenticator { +class ResourceOwnerPasswordGrantAuthenticator implements AuthenticatorInterface { private OAuth2TokenReceiver $_tokenReceiver; public function __construct($clientId, $userName, $password, $tokenEndpoint) { @@ -15,7 +15,7 @@ public function __construct($clientId, $userName, $password, $tokenEndpoint) { /** * @throws VaasAuthenticationException */ - public function getToken() { + public function getToken(): string { return $this->_tokenReceiver->GetToken(); } } diff --git a/php/src/vaas/Message/VerdictResponse.php b/php/src/vaas/Message/VerdictResponse.php index f6c603d2..e706ae65 100644 --- a/php/src/vaas/Message/VerdictResponse.php +++ b/php/src/vaas/Message/VerdictResponse.php @@ -7,6 +7,7 @@ class VerdictResponse extends BaseMessage public Verdict $verdict; public ?string $url; public string $guid; + public string $requestId; public string $sha256; public ?string $upload_token; public ?string $file_type; diff --git a/php/src/vaas/Vaas.php b/php/src/vaas/Vaas.php index 07ff5c99..be5a458d 100644 --- a/php/src/vaas/Vaas.php +++ b/php/src/vaas/Vaas.php @@ -2,7 +2,6 @@ namespace VaasSdk; -use Amp\ByteStream\ReadableResourceStream; use Amp\ByteStream\ReadableStream; use Amp\DeferredCancellation; use Amp\Http\Client\HttpClient; @@ -12,21 +11,13 @@ use Amp\Http\Client\StreamedContent; use Amp\TimeoutCancellation; use InvalidArgumentException; -use JsonMapper; use JsonMapper_Exception; use Ramsey\Uuid\Rfc4122\UuidV4; use VaasSdk\Exceptions\TimeoutException; use VaasSdk\Exceptions\UploadFailedException; -use VaasSdk\Exceptions\VaasAuthenticationException; -use VaasSdk\Exceptions\VaasClientException; -use VaasSdk\Exceptions\VaasConnectionClosedException; use VaasSdk\Exceptions\VaasInvalidStateException; use VaasSdk\Exceptions\VaasServerException; -use VaasSdk\Message\AuthRequest; -use VaasSdk\Message\AuthResponse; -use VaasSdk\Message\Error; use VaasSdk\Message\Verdict; -use VaasSdk\Message\Kind; use VaasSdk\Message\VerdictRequest; use VaasSdk\Message\VerdictRequestForStream; use VaasSdk\Message\VerdictResponse; @@ -35,51 +26,94 @@ use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Revolt\EventLoop; -use VaasSdk\Message\BaseMessage; +use VaasSdk\Authentication\AuthenticatorInterface; +use VaasSdk\Exceptions\VaasClientException; use VaasSdk\Message\VaasVerdict; use WebSocket\BadOpcodeException; -use WebSocket\Message\Close; -use WebSocket\Message\Ping; class Vaas { - private string $_vaasUrl = "wss://gateway.production.vaas.gdatasecurity.de"; - private VaasConnection $_vaasConnection; - private int $_waitTimeoutInSeconds = 600; - private int $_uploadTimeoutInSeconds = 600; - private LoggerInterface $_logger; - private VaasOptions $_options; - private HttpClient $_httpClient; - private JsonMapper $_jsonMapper; + private VaasConnection $vaasConnection; + private int $uploadTimeoutInSeconds = 600; + private VaasOptions $options; + private HttpClient $httpClient; + private ?AuthenticatorInterface $authenticator = null; + private ?LoggerInterface $logger; + private ?string $vaasUrl = "wss://gateway.production.vaas.gdatasecurity.de"; + + public function __destruct() { + if (isset($this->vaasConnection)) { + $this->vaasConnection->close(); + } + } - /** - */ - public function __construct(?string $vaasUrl, ?LoggerInterface $logger = new NullLogger(), VaasOptions $options = new VaasOptions()) + public function withOptions(VaasOptions $options): self { - $this->_options = $options; - $this->_httpClient = HttpClientBuilder::buildDefault(); - $this->_logger = $logger; - $this->_logger->debug("Url: " . $vaasUrl); - if ($vaasUrl) - $this->_vaasUrl = $vaasUrl; - $this->_jsonMapper = new JsonMapper(); - $this->_jsonMapper->bStrictObjectTypeChecking = false; + $this->options = $options; + return $this; } - /** - */ - public function Connect( - string $token, - ?VaasConnection $vaasConnection = null - ) { - $this->_vaasConnection = $vaasConnection ?? new VaasConnection($this->_vaasUrl); - $webSocket = $this->_vaasConnection->GetConnectedWebsocket(); - - $authRequest = new AuthRequest($token); - $webSocket->send(json_encode($authRequest)); - $authResponse = $this->_waitForAuthResponse(); - $this->_logger->debug("Authenticated: " . json_encode($authResponse)); - $this->_vaasConnection->SessionId = $authResponse->session_id; + public function withHtttpClient(HttpClient $httpClient): self + { + $this->httpClient = $httpClient; + return $this; + } + + public function withAuthenticator(AuthenticatorInterface $authenticator): self + { + $this->authenticator = $authenticator; + return $this; + } + + public function withLogger(LoggerInterface $logger): self + { + $this->logger = $logger; + return $this; + } + + public function withUrl(string $vaasUrl): self + { + $this->vaasUrl = $vaasUrl; + return $this; + } + + public function withVaasConnection(VaasConnection $vaasConnection): self + { + $this->vaasConnection = $vaasConnection; + return $this; + } + + public function build(): self + { + if (!isset($this->logger)) { + $this->logger = new NullLogger(); + } + if (!isset($this->vaasConnection) && isset($this->authenticator)) { + $this->vaasConnection = (new VaasConnection()) + ->withAuthenticator($this->authenticator) + ->withUrl($this->vaasUrl) + ->withLogger($this->logger) + ->build(); + } else if (!isset($this->vaasConnection)) { + $this->vaasConnection = (new VaasConnection()) + ->withUrl($this->vaasUrl) + ->withLogger($this->logger) + ->build(); + } + if (!isset($this->options)) { + $this->options = new VaasOptions(); + } + if (!isset($this->httpClient)) { + $this->httpClient = HttpClientBuilder::buildDefault(); + } + return $this; + } + + public function Connect(string $token = "") { + if (!isset($this->vaasConnection)) { + throw new VaasInvalidStateException("No VaasConnection given and build() was not called"); + } + $this->vaasConnection->Connect($token); } /** @@ -93,9 +127,8 @@ public function Connect( * * @return VaasVerdict the verdict */ - public function ForSha256(string $hashString, string $uuid = null): VaasVerdict - { - $this->_logger->debug("ForSha256WithFlags", ["Sha256" => $hashString]); + public function ForSha256(string $hashString, string $uuid = null): VaasVerdict { + $this->logger->debug("ForSha256WithFlags", ["Sha256" => $hashString]); $sha256 = Sha256::TryFromString($hashString); @@ -120,7 +153,7 @@ public function ForSha256(string $hashString, string $uuid = null): VaasVerdict */ public function ForUrl(?string $url, string $uuid = null): VaasVerdict { - $this->_logger->debug("ForUrlWithFlags", ["URL:" => $url]); + $this->logger->debug("ForUrlWithFlags", ["URL:" => $url]); if (!filter_var($url, FILTER_VALIDATE_URL)) { throw new \InvalidArgumentException("Url is not valid"); @@ -148,24 +181,29 @@ public function ForUrl(?string $url, string $uuid = null): VaasVerdict */ public function ForFile(string $path, $upload = true, string $uuid = null): VaasVerdict { - $this->_logger->debug("ForFileWithFlags", ["File" => $path]); + $this->logger->debug("ForFileWithFlags", ["File" => $path]); $sha256 = Sha256::TryFromFile($path); - $this->_logger->debug("Calculated Hash", ["Sha256" => $sha256]); + $this->logger->debug("Calculated Hash", ["Sha256" => $sha256]); $verdictResponse = $this->_verdictResponseForSha256( $sha256, $uuid ); if ($verdictResponse->verdict == Verdict::UNKNOWN && $upload === true) { - $this->_logger->debug("UploadToken", ["UploadToken" => $verdictResponse->upload_token]); + $this->logger->debug("UploadToken", ["UploadToken" => $verdictResponse->upload_token]); - $fileStream = new ReadableResourceStream(\fopen($path, 'r')); + $fileStream = \Amp\File\openFile($path, 'r'); $fileSize = \filesize($path); - - $this->UploadStream($fileStream, $verdictResponse->url, $verdictResponse->upload_token, $fileSize); - return new VaasVerdict($this->_waitForVerdict($verdictResponse->guid)); + return new VaasVerdict( + $this->UploadStream( + $fileStream, + $verdictResponse->url, + $verdictResponse->upload_token, + $fileSize, + $verdictResponse->guid) + ); } return new VaasVerdict($verdictResponse); @@ -188,9 +226,9 @@ public function ForFile(string $path, $upload = true, string $uuid = null): Vaas */ public function ForStream(ReadableStream $stream, int $size = 0, string $uuid = null): VaasVerdict { - $this->_logger->debug("uuid: ".var_export($uuid, true)); + $this->logger->debug("uuid: ".var_export($uuid, true)); $uuid = $uuid ?? UuidV4::getFactory()->uuid4()->toString(); - $this->_logger->debug("uuid: ".var_export($uuid, true)); + $this->logger->debug("uuid: ".var_export($uuid, true)); $verdictResponse = $this->_verdictResponseForStream($uuid); if ($verdictResponse->verdict != Verdict::UNKNOWN) { @@ -203,179 +241,16 @@ public function ForStream(ReadableStream $stream, int $size = 0, string $uuid = throw new JsonMapper_Exception("VerdictResponse missing URL for stream upload."); } - $this->UploadStream($stream, $verdictResponse->url, $verdictResponse->upload_token, $size); - - $verdictResponse = $this->_waitForVerdict($uuid); - - return new VaasVerdict($verdictResponse); - } - - /** - * @return AuthResponse - * @throws VaasConnectionClosedException - * @throws JsonMapper_Exception - * @throws TimeoutException - * @throws VaasAuthenticationException - * @throws VaasClientException - * @throws VaasInvalidStateException - * @throws VaasServerException - */ - private function _waitForAuthResponse(): AuthResponse - { - $websocket = $this->_vaasConnection->GetConnectedWebsocket(); - $this->_logger->debug("WaitForAuthResponse"); - - $start_time = time(); - - while (true) { - if ((time() - $start_time) > $this->_waitTimeoutInSeconds) { - throw new TimeoutException(); - } - - $result = null; - try { - $result = $websocket->receive(); - } catch (\WebSocket\TimeoutException $e) { - $this->_logger->debug("Read timeout, send ping"); - $websocket->ping(); - } - - if ($result != null) { - if ($result instanceof Ping) { - $websocket->pong(); - continue; - } - if ($result instanceof Close) { - throw new VaasServerException("Connection closed"); - } - $result = $result->getContent(); - $this->_logger->debug("Result", json_decode($result, true)); - $genericObject = \json_decode($result); - $resultObject = $this->_jsonMapper->map( - $genericObject, - BaseMessage::class - ); - if ($resultObject->kind == Kind::AuthResponse) { - $authResponse = $this->_jsonMapper->map( - $genericObject, - AuthResponse::class - ); - $this->_logger->debug($result); - if ($authResponse->success === false) { - throw new VaasAuthenticationException($result); - } - return $authResponse; - } - if ($resultObject->kind == Kind::Error) { - try { - $errorResponse = $this->_jsonMapper->map( - $genericObject, - Error::class - ); - } catch (JsonMapper_Exception $e) { - // Received error type is not deserializable to Error - throw new VaasServerException($e->getMessage()); - } - $this->_handleWebSocketErrorResponse($errorResponse); - } - } - sleep(1); - } - } - - /** - * @param string $guid - * @return VerdictResponse - * @throws JsonMapper_Exception - * @throws TimeoutException - * @throws VaasClientException - * @throws VaasInvalidStateException - * @throws VaasServerException - */ - private function _waitForVerdict(string $guid): VerdictResponse - { - $this->_logger->debug("WaitForVerdict"); - $start_time = time(); - - if (!isset($this->_vaasConnection)) { - throw new VaasInvalidStateException("connect() was not called"); - } - while (true) { - $websocket = $this->_vaasConnection->GetAuthenticatedWebsocket(); - if ((time() - $start_time) > $this->_waitTimeoutInSeconds) { - throw new TimeoutException(); - } - $result = null; - try { - $result = $websocket->receive(); - } catch (\WebSocket\TimeoutException $e) { - $this->_logger->debug("Read timeout, send ping"); - $websocket->ping(); - } - if ($result != null) { - if ($result instanceof Ping) { - $websocket->pong(); - continue; - } - if ($result instanceof Close) { - throw new VaasServerException("Connection closed"); - } - $result = $result->getContent(); - $this->_logger->debug("Result", json_decode($result, true)); - $resultObject = json_decode($result); - $baseMessage = $this->_jsonMapper->map( - $resultObject, - new BaseMessage() - ); - if ($baseMessage->kind == Kind::Error) { - try { - $errorResponse = $this->_jsonMapper->map( - $resultObject, - new Error() - ); - } catch (JsonMapper_Exception $e) { - // Received error type is not deserializable to Error - throw new VaasServerException($e->getMessage()); - } - $this->_handleWebSocketErrorResponse($errorResponse); - } - if ($baseMessage->kind != Kind::VerdictResponse) { - continue; - } - - $verdictResponse = $this->_jsonMapper->map( - $resultObject, - new VerdictResponse() - ); - if (!isset($verdictResponse->guid) || !isset($verdictResponse->kind)) { - continue; - } - - if ($verdictResponse->guid == $guid) { - return $verdictResponse; - } - } - } - } - - /** - * @throws VaasServerException - * @throws VaasClientException - */ - private function _handleWebSocketErrorResponse(Error $errorResponse): void - { - if (isset($errorResponse->problem_details->detail)) { - $details = $errorResponse->problem_details->detail; - } else { - $details = null; - } - $errorType = $errorResponse->type; - if ($errorType == "ClientError") { - throw new VaasClientException($details); - } - throw new VaasServerException($details); + return new VaasVerdict( + $this->UploadStream( + $stream, + $verdictResponse->url, + $verdictResponse->upload_token, + $size, + $uuid) + ); } - + /** * @throws TimeoutException * @@ -383,21 +258,15 @@ private function _handleWebSocketErrorResponse(Error $errorResponse): void */ private function _verdictResponseForSha256(Sha256 $sha256, string $uuid = null): VerdictResponse { - $this->_logger->debug("_verdictResponseForSha256"); + $this->logger->debug("_verdictResponseForSha256"); - if (!isset($this->_vaasConnection)) { - throw new VaasInvalidStateException("connect() was not called"); + if (!isset($this->vaasConnection->SessionId)) { + throw new VaasInvalidStateException("No Authenticator given and connect() was not called"); } - $websocket = $this->_vaasConnection->GetAuthenticatedWebsocket(); - - $request = new VerdictRequest(strtolower($sha256), $uuid, $this->_vaasConnection->SessionId); - $request->use_cache = $this->_options->UseCache; - $request->use_hash_lookup = $this->_options->UseHashLookup; - $websocket->send(json_encode($request)); - - $this->_logger->debug("verdictResponse", ["VerdictResponse" => json_encode($request)]); - - return $this->_waitForVerdict($request->guid); + $request = new VerdictRequest(strtolower($sha256), $uuid, $this->vaasConnection->SessionId); + $request->use_cache = $this->options->UseCache; + $request->use_hash_lookup = $this->options->UseHashLookup; + return $this->vaasConnection->SendRequest(json_encode($request), $request->guid)->await(); } /** @@ -407,21 +276,15 @@ private function _verdictResponseForSha256(Sha256 $sha256, string $uuid = null): */ private function _verdictResponseForUrl(string $url, string $uuid = null): VerdictResponse { - $this->_logger->debug("_verdictResponseForUrl"); + $this->logger->debug("_verdictResponseForUrl"); - if (!isset($this->_vaasConnection)) { - throw new VaasInvalidStateException("connect() was not called"); + if (!isset($this->vaasConnection->SessionId)) { + throw new VaasInvalidStateException("No Authenticator given and connect() was not called"); } - $websocket = $this->_vaasConnection->GetAuthenticatedWebsocket(); - - $request = new VerdictRequestForUrl($url, $uuid, $this->_vaasConnection->SessionId); - $request->use_cache = $this->_options->UseCache; - $request->use_hash_lookup = $this->_options->UseHashLookup; - $websocket->send(json_encode($request)); - - $this->_logger->debug("verdictResponse", ["VerdictResponse" => json_encode($request)]); - - return $this->_waitForVerdict($request->guid); + $request = new VerdictRequestForUrl($url, $uuid, $this->vaasConnection->SessionId); + $request->use_cache = $this->options->UseCache; + $request->use_hash_lookup = $this->options->UseHashLookup; + return $this->vaasConnection->SendRequest(json_encode($request), $request->guid)->await(); } /** @@ -434,21 +297,15 @@ private function _verdictResponseForUrl(string $url, string $uuid = null): Verdi */ private function _verdictResponseForStream(string $uuid = null): VerdictResponse { - $this->_logger->debug("_verdictResponseForStream"); + $this->logger->debug("_verdictResponseForStream"); - if (!isset($this->_vaasConnection)) { - throw new VaasInvalidStateException("connect() was not called"); + if (!isset($this->vaasConnection->SessionId)) { + throw new VaasInvalidStateException("No Authenticator given and connect() was not called"); } - $websocket = $this->_vaasConnection->GetAuthenticatedWebsocket(); - - $request = new VerdictRequestForStream($this->_vaasConnection->SessionId, $uuid); - $request->use_cache = $this->_options->UseCache; - $request->use_hash_lookup = $this->_options->UseHashLookup; - $websocket->send(json_encode($request)); - - $this->_logger->debug("verdictResponse", ["VerdictResponse" => json_encode($request)]); - - return $this->_waitForVerdict($request->guid); + $request = new VerdictRequestForStream($this->vaasConnection->SessionId, $uuid); + $request->use_cache = $this->options->UseCache; + $request->use_hash_lookup = $this->options->UseHashLookup; + return $this->vaasConnection->SendRequest(json_encode($request), $request->guid)->await(); } /** @@ -460,20 +317,7 @@ private function _verdictResponseForStream(string $uuid = null): VerdictResponse */ public function setWebsocketTimeOut(int $timeoutInSeconds): void { - $this->_vaasConnection->WebSocketClient->setTimeout($timeoutInSeconds); - } - - /** - * Sets the timeout in seconds for the loops were we wait for a verdict - * - * @param int $timeoutInSeconds timeout for the websocket - * - * @return Vaas - */ - public function setWaitTimeoutInSeconds(int $timeoutInSeconds): self - { - $this->_waitTimeoutInSeconds = $timeoutInSeconds; - return $this; + $this->vaasConnection->setTimeout($timeoutInSeconds); } /** @@ -485,41 +329,33 @@ public function setWaitTimeoutInSeconds(int $timeoutInSeconds): self */ public function setUploadTimeout(int $UploadTimeoutInSeconds): self { - $this->_uploadTimeoutInSeconds = $UploadTimeoutInSeconds; + $this->uploadTimeoutInSeconds = $UploadTimeoutInSeconds; return $this; } - /** - * Uploads a file stream to a specified URL using a given upload token and file size. - * - * @param ReadableStream $fileStream The file stream to upload. - * @param string $url The URL to upload the file to. - * @param string $uploadToken The upload token to authenticate the upload. - * @param int $fileSize The size of the file being uploaded. - * @throws UploadFailedException If the upload fails. - * @throws VaasClientException If there is an error with the Vaas client. - * @return void - */ - private function UploadStream(ReadableStream $fileStream, string $url, string $uploadToken, int $fileSize): void + private function UploadStream( + ReadableStream $fileStream, + string $url, string $uploadToken, int $fileSize, + string $requestId): VerdictResponse { $cancellation = new DeferredCancellation(); $times = 0; $pingTimer = EventLoop::repeat(5, function () use(&$times) { - $this->_logger->debug("pinging " . $times++); - $websocket = $this->_vaasConnection->GetAuthenticatedWebsocket(); + $this->logger->debug("pinging " . $times++); + $websocket = $this->vaasConnection->GetAuthenticatedWebsocket(); $websocket->ping(); }); + $futureResponse = $this->vaasConnection->GetResponse($requestId); try { $request = new Request($url, 'PUT'); $request->setProtocolVersions(["1.1"]); - $request->setTransferTimeout($this->_uploadTimeoutInSeconds); + $request->setTransferTimeout($this->uploadTimeoutInSeconds); $request->setBody(StreamedContent::fromStream($fileStream, $fileSize)); $request->addHeader("Content-Length", $fileSize); $request->addHeader("Authorization", $uploadToken); - $response = $this->_httpClient->request( - $request, new TimeoutCancellation($this->_uploadTimeoutInSeconds), $cancellation->getCancellation()); + $response = $this->httpClient->request($request, new TimeoutCancellation($this->uploadTimeoutInSeconds)); if ($response->getStatus() > 399) { $reason = $response->getBody()->buffer($cancellation->getCancellation()); throw new UploadFailedException($reason, $response->getStatus()); @@ -532,6 +368,7 @@ private function UploadStream(ReadableStream $fileStream, string $url, string $u } finally { EventLoop::cancel($pingTimer); $cancellation->cancel(); + return $futureResponse->getFuture()->await(); } } } diff --git a/php/src/vaas/VaasConnection.php b/php/src/vaas/VaasConnection.php index 7e970c19..9e28e353 100644 --- a/php/src/vaas/VaasConnection.php +++ b/php/src/vaas/VaasConnection.php @@ -2,41 +2,169 @@ namespace VaasSdk; +use Amp\Cache\LocalCache; +use Amp\CancelledException; +use Amp\DeferredCancellation; +use Amp\DeferredFuture; +use Amp\Future; +use Amp\Websocket\Client\WebsocketConnection; +use Exception; +use JsonMapper; +use JsonMapper_Exception; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Revolt\EventLoop; +use VaasSdk\Authentication\AuthenticatorInterface; +use VaasSdk\Exceptions\VaasAuthenticationException; +use VaasSdk\Exceptions\VaasClientException; use VaasSdk\Exceptions\VaasConnectionClosedException; use VaasSdk\Exceptions\VaasInvalidStateException; -use WebSocket\Client; +use VaasSdk\Exceptions\VaasServerException; +use VaasSdk\Message\AuthRequest; +use VaasSdk\Message\AuthResponse; +use VaasSdk\Message\BaseMessage; +use VaasSdk\Message\Error; +use VaasSdk\Message\Kind; +use VaasSdk\Message\VerdictResponse; + +use function Amp\async; +use function Amp\Websocket\Client\connect; class VaasConnection { - public Client $WebSocketClient; public string $SessionId; - public function __construct(string $url, Client $WebSocketClient = null) - { - if (!isset($WebSocketClient)) - $this->WebSocketClient = new Client($url, [ - "filter" => [ - 'text', 'binary', 'ping' - ], - "return_obj" => true - ]); + private WebsocketConnection $WebSocketClient; + private int $waitTimeoutInSeconds = 600; + private string $url = "wss://gateway.production.vaas.gdatasecurity.de"; + private AuthenticatorInterface $authenticator; + private LocalCache $responses; + private LoggerInterface $logger; + private ?Future $loop; + private ?DeferredCancellation $loopCancellation; + + public function __construct() { + $this->responses = new LocalCache(); + $this->loopCancellation = new DeferredCancellation(); + } + + public function close(): void { + if ($this->loopCancellation != null) { + $this->loopCancellation->cancel(); + } + $this->loop->ignore(); + } + + public function withAuthenticator(AuthenticatorInterface $authenticator): VaasConnection { + $this->authenticator = $authenticator; + return $this; + } + + public function withConnection(WebsocketConnection $WebSocketClient): VaasConnection { + $this->WebSocketClient = $WebSocketClient; + return $this; + } + + public function withUrl(string $url): VaasConnection { + $this->url = $url; + return $this; + } + + public function withLogger(LoggerInterface $logger): VaasConnection { + $this->logger = $logger; + return $this; + } + + public function withTimeout(int $timeoutInSeconds): VaasConnection { + $this->waitTimeoutInSeconds = $timeoutInSeconds; + return $this; + } + + public function build(): VaasConnection { + if (!isset($this->WebSocketClient)) { + $this->WebSocketClient = connect($this->url); + } + $this->loop = async(function() { + $this->handleResponse(); + })->catch(function($e) { + if (!$e instanceof CancelledException) { + $this->logger->error("Error", ["error" => $e]); + } + $futures = $this->responses->getIterator(); + foreach($futures as $future) { + $future->error($e); + } + }); + if (isset($this->authenticator)) { + $this->Connect(); + } + if (!isset($this->logger)) { + $this->logger = new NullLogger(); + } + return $this; + } + + public function Connect(string $token = ""): void { + if ($token === "" && !isset($this->authenticator)) { + throw new VaasInvalidStateException("Authenticator not set and no token given"); + } + + if ($token !== "") + $authRequest = new AuthRequest($token); else - $this->WebSocketClient = $WebSocketClient; - $this->WebSocketClient->ping(); + $authRequest = new AuthRequest($this->authenticator->getToken()); + + $futureResponse = $this->SendAuthRequest(json_encode($authRequest)); + $authResponse = $futureResponse->await(); + $this->SessionId = $authResponse->session_id; + } + + private function SendAuthRequest(string $message): Future { + $webSocket = $this->GetConnectedWebsocket(); + return $this->Send($webSocket, $message, AuthRequest::class); + } + + public function SendRequest(string $message, $requestId): Future { + $webSocket = $this->GetAuthenticatedWebsocket(); + return $this->Send($webSocket, $message, $requestId); } - public function GetConnectedWebsocket(): Client + public function Send(WebsocketConnection &$webSocket, string $message, $requestId): Future { + $deferred = $this->GetResponse($requestId); + EventLoop::delay($this->waitTimeoutInSeconds, function() use ($deferred, $requestId) { + if ($deferred->isComplete()) return; + $this->responses->delete($requestId); + $deferred->error(new VaasClientException("Request timed out")); + }); + + $webSocket->sendText($message); + return $deferred->getFuture(); + } + + public function GetResponse($requestId): DeferredFuture { + $future = new DeferredFuture(); + $this->responses->set($requestId, $future); + return $future; + } + + public function GetConnectedWebsocket(): WebsocketConnection { - if (!$this->WebSocketClient) { + if (!isset($this->WebSocketClient)) { + foreach($this->responses->getIterator() as $future) { + $future->error(new VaasInvalidStateException("connect() was not called")); + } throw new VaasInvalidStateException("connect() was not called"); } - if (!$this->WebSocketClient->isConnected()) { + if ($this->WebSocketClient->isClosed()) { + foreach($this->responses->getIterator() as $future) { + $future->error(new VaasConnectionClosedException()); + } throw new VaasConnectionClosedException(); } return $this->WebSocketClient; } - - public function GetAuthenticatedWebsocket(): Client + + public function GetAuthenticatedWebsocket(): WebsocketConnection { $websocket = $this->GetConnectedWebsocket(); if (!isset($this->SessionId) || !$this->SessionId) { @@ -46,4 +174,102 @@ public function GetAuthenticatedWebsocket(): Client } return $websocket; } + + public function setTimeout(int $timeoutInSeconds): void { + $this->waitTimeoutInSeconds = $timeoutInSeconds; + } + + private function handleResponse(): void { + $mapper = new JsonMapper(); + $mapper->bStrictObjectTypeChecking = false; + $connection = $this->GetConnectedWebsocket(); + while ($message = $connection->receive($this->loopCancellation->getCancellation())) { + if ($message == null) continue; + if (!$message->isText()) continue; + $messageText = $message->read($this->loopCancellation->getCancellation()); + if ($messageText == null) throw new VaasConnectionClosedException(); + + $this->logger->debug("Result", json_decode($messageText, true)); + $resultObject = json_decode($messageText); + $baseMessage = $mapper->map($resultObject, BaseMessage::class); + try { + switch($baseMessage->kind) { + case Kind::AuthResponse: + $authResponse = $mapper->map($resultObject, AuthResponse::class); + assert($authResponse instanceof AuthResponse); + $futureResponse = $this->responses->get(AuthRequest::class); + if ($futureResponse == null) { + throw new VaasClientException("No future response found for auth request"); + } + $this->responses->delete(AuthRequest::class); + assert($futureResponse instanceof DeferredFuture); + if ($authResponse->success === false) { + $futureResponse->error(new VaasAuthenticationException("Authentication failed")); + } else { + $futureResponse->complete($authResponse); + } + $this->responses->delete(AuthRequest::class); + break; + case Kind::VerdictResponse: + $verdictResponse = $mapper->map($resultObject, VerdictResponse::class); + $futureResponse = $this->ValidateResponseAndGetFuture($verdictResponse); + if ($futureResponse == null) { + break; + } + $futureResponse->complete($verdictResponse); + break; + case Kind::Error: + $errorResponse = $mapper->map($resultObject, Error::class); + $futureResponse = $this->ValidateResponseAndGetFuture($errorResponse); + if ($futureResponse == null) { + break; + } + $futureResponse->error($this->_handleWebSocketErrorResponse($errorResponse)); + break; + default: + throw new VaasServerException("Unknown message kind: " . $baseMessage->kind); + }; + } catch (JsonMapper_Exception $e) { + throw new VaasServerException("Error parsing received message: " . $e->getMessage()); + } + } + } + + private function ValidateResponseAndGetFuture(Error|VerdictResponse $message): ?DeferredFuture { + $requestId = $message->requestId ?? $message->guid; + + if (isset($requestId) == null && $message instanceof VerdictResponse) { + foreach($this->responses->getIterator() as $future) { + $future->error(new VaasServerException("No guid found in verdict response")); + } + } + if ($requestId == null && $message instanceof Error) { + foreach($this->responses->getIterator() as $future) { + $future->error(new VaasClientException($message->problem_details->detail)); + } + return null; + } + $futureResponse = $this->responses->get($requestId); + if ($futureResponse == null) { + foreach($this->responses->getIterator() as $future) { + $future->error(new VaasClientException("No future response found for guid: " .$requestId)); + } + } + $this->responses->delete($requestId); + return $futureResponse; + } + + private function _handleWebSocketErrorResponse(Error $errorResponse): Exception + { + if (isset($errorResponse->problem_details->detail)) { + $details = $errorResponse->problem_details->detail; + } else { + $details = null; + } + $errorType = $errorResponse->type; + if ($errorType == "ClientError") { + return new VaasClientException($details); + } + return new VaasServerException($details); + } } \ No newline at end of file diff --git a/php/src/vaas/composer.json b/php/src/vaas/composer.json index bbc19cbe..40c49836 100644 --- a/php/src/vaas/composer.json +++ b/php/src/vaas/composer.json @@ -15,11 +15,13 @@ "require": { "php": "^8.1", "ramsey/uuid": "^4.7 || ^4.2", - "textalk/websocket": "^1.6 || ^1.5", "netresearch/jsonmapper": "^5.0", "psr/log": "^1.1 || ^2.0 || ^3.0", "amphp/http-client": "5.1.0", - "amphp/file": "3.1.1" + "amphp/file": "3.1.1", + "amphp/websocket-client": "2.0.0", + "amphp/amp": "3.0.2", + "amphp/cache": "2.0.1" }, "autoload": { "psr-4": { diff --git a/php/tests/vaas/ProtocolTest.php b/php/tests/vaas/ProtocolTest.php index 93332ea8..753aaa95 100644 --- a/php/tests/vaas/ProtocolTest.php +++ b/php/tests/vaas/ProtocolTest.php @@ -2,6 +2,7 @@ namespace VaasTesting; +use Amp\Websocket\WebsocketMessage; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use Psr\Log\NullLogger; @@ -19,41 +20,58 @@ public function testForConnectWithInvalidToken_ThrowsAccessDeniedException(): vo { $this->expectException(VaasAuthenticationException::class); - $fakeWebsocket = $this->createStub(\WebSocket\Client::class); + $fakeWebsocket = $this->createStub(\Amp\Websocket\Client\WebsocketConnection::class); $fakeWebsocket->method('ping'); - $fakeWebsocket->method('send'); - $fakeWebsocket->method('isConnected') - ->willReturn(true); + $fakeWebsocket->method('isClosed') + ->willReturn(false); $fakeWebsocket->method('receive') - ->willReturn(new \WebSocket\Message\Text('{"kind": "AuthResponse", "success": false}')); + ->willReturn(WebsocketMessage::fromText('{"kind": "AuthResponse", "success": false}')); $vaasConnection = new VaasConnection("", $fakeWebsocket); - (new Vaas("url"))->Connect("invalid", $vaasConnection); + (new Vaas("url"))->build()->Connect("invalid", $vaasConnection); } public function testConnectionGetsClosedAfterConnecting_ThrowsVaasConnectionClosedException(): void { $this->expectException(VaasConnectionClosedException::class); - $fakeWebsocket = $this->createStub(\WebSocket\Client::class); + $fakeWebsocket = $this->createStub(\Amp\Websocket\Client\WebsocketConnection::class); $fakeWebsocket->method('ping'); - $fakeWebsocket->method('send'); - $fakeWebsocket->method('isConnected') - ->willReturn(true, true, false); + $fakeWebsocket->method('isClosed') + ->willReturn(false, true); $fakeWebsocket->method('receive') - ->willReturn(new \WebSocket\Message\Text('{"kind": "AuthResponse", "success": true, "session_id": "id"}')); - $vaasConnection = new VaasConnection("", $fakeWebsocket); + ->willReturn(WebsocketMessage::fromText('{"kind": "AuthResponse", "success": true, "session_id": "id"}')); + $vaasConnection = (new VaasConnection()) + ->withConnection($fakeWebsocket) + ->build(); - $vaas = new Vaas("url", new NullLogger()); - $vaas->Connect("valid", $vaasConnection); + $vaas = (new Vaas()) + ->withUrl("wws://url.de") + ->withVaasConnection($vaasConnection) + ->build(); + $vaas->Connect("valid"); $vaas->ForSha256("000005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8"); } - public function testForSha256CallBeforeConnection_ThrowsVaasInvalidStateException(): void + public function testConnectionGetsClosedBeforeConnect_ThrowsVaasConnectionClosedException(): void { - $this->expectException(VaasInvalidStateException::class); - $vaas = new Vaas("url"); - $vaas->ForSha256("000005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8"); + $this->expectException(VaasConnectionClosedException::class); + + $fakeWebsocket = $this->createStub(\Amp\Websocket\Client\WebsocketConnection::class); + $fakeWebsocket->method('ping'); + $fakeWebsocket->method('isClosed') + ->willReturn(true); + $fakeWebsocket->method('receive') + ->willReturn(WebsocketMessage::fromText('{"kind": "AuthResponse", "success": true, "session_id": "id"}')); + $vaasConnection = (new VaasConnection()) + ->withConnection($fakeWebsocket) + ->build(); + + $vaas = (new Vaas()) + ->withUrl("wws://url.de") + ->withVaasConnection($vaasConnection) + ->build(); + $vaas->Connect("valid"); } public function testVerdictRequestSerializationTest(): void diff --git a/php/tests/vaas/VaasTest.php b/php/tests/vaas/VaasTest.php index 6eb94ded..814b5386 100644 --- a/php/tests/vaas/VaasTest.php +++ b/php/tests/vaas/VaasTest.php @@ -3,7 +3,6 @@ namespace VaasTesting; use Amp\ByteStream\Pipe; -use Amp\ByteStream\WritableBuffer; use Amp\Http\Client\HttpClient; use Amp\Http\Client\HttpClientBuilder; use Amp\Http\Client\Request; @@ -36,6 +35,7 @@ use WebSocket\BadOpcodeException; use function Amp\ByteStream\Internal\tryToCreateReadableStreamFromResource; +use function Amp\delay; final class VaasTest extends TestCase { @@ -79,7 +79,11 @@ public function setUp(): void private function _getVaas(bool $useCache = false, bool $useHashLookup = true, LoggerInterface $logger = null): Vaas { - return new Vaas($_ENV["VAAS_URL"], $logger ?? $this->_getDebugLogger(), new VaasOptions($useCache, $useHashLookup)); + return (new Vaas()) + ->withUrl($_ENV["VAAS_URL"]) + ->withLogger($logger ?? $this->_getDebugLogger()) + ->withOptions(new VaasOptions($useCache, $useHashLookup)) + ->build(); } private function _getDebugLogger(): LoggerInterface @@ -135,18 +139,18 @@ public function testForSha256MaliciousSha256_WithResourceOwnerPasswordAuthentica $this->assertEqualsIgnoringCase(self::MALICIOUS_HASH, $verdict->Sha256); } - public function testForConnectingWithInvalidToken_ThrowsVaasAccessDeniedException() + public function testForCallingTheConnectFunctionWithoutBuildOrGivenConnection_ThrowsInvalidStateException(): void { - $this->expectException(VaasAuthenticationException::class); - $vaas = $this->_getVaas(); - $vaas->Connect("invalid"); + $this->expectException(VaasInvalidStateException::class); + $vaas = new Vaas(); + $vaas->Connect(""); } - public function testForRequestHashBeforeConnec_ThrowsVaasInvalidStateException() + public function testForConnectingWithInvalidToken_ThrowsVaasAccessDeniedException() { - $this->expectException(VaasInvalidStateException::class); + $this->expectException(VaasAuthenticationException::class); $vaas = $this->_getVaas(); - $vaas->ForSha256(self::MALICIOUS_HASH, "someuuid"); + $vaas->Connect("invalid"); } public function testForSha256MaliciousSha256_GetsMaliciousResponse(): void @@ -175,6 +179,24 @@ public function testForSha256MaliciousSha256WithFlag_BothFlagsFalse_GetsMaliciou $this->assertEqualsIgnoringCase(self::MALICIOUS_HASH, $verdict->Sha256); } + public function test60SecondsWaitAfterConnect_DoesNotLoseConnection(): void + { + $this->markTestSkipped("this test should not run in ci"); + $uuid = $this->getUuid(); + $cleanSha256 = "cd617c5c1b1ff1c94a52ab8cf07192654f271a3f8bad49490288131ccb9efc1e"; + + $vaas = $this->_getVaas(); + $vaas->Connect($this->getClientCredentialsGrantAuthenticator()->getToken()); + + delay(60); + + $verdict = $vaas->ForSha256($cleanSha256, $uuid); + + $this->assertEquals(Verdict::CLEAN, $verdict->Verdict); + $this->assertEquals($uuid, $verdict->Guid); + $this->assertEqualsIgnoringCase($cleanSha256, $verdict->Sha256); + } + public function testForSha256CleanSha256_GetsCleanResponse(): void { $uuid = $this->getUuid(); @@ -450,6 +472,24 @@ public function testForUrl_WithInvalidUrl_ThrowsVaasClientException() $this->_getDebugLogger()->info("Verdict for URL " . $invalidUrl . " is " . $verdict->Verdict); } + /** + * @throws VaasAuthenticationException + * @throws TimeoutException + */ + public function testForUrl_NoTokenNoAuthenticator_ThrowsInvalidStateException() + { + $vaas = $this->_getVaas(); + $this->expectException(VaasInvalidStateException::class); + $vaas->ForUrl("http://gdata.de"); + } + + public function testForUrl_CallConnectWithoutToken_ThrowsInvalidStateException() + { + $vaas = $this->_getVaas(); + $this->expectException(VaasInvalidStateException::class); + $vaas->Connect(); + } + /** * @throws VaasAuthenticationException * @throws TimeoutException