diff --git a/php/examples/VaasExample/AuthenticationExamples.php b/php/examples/VaasExample/AuthenticationExamples.php index aeea5354..2c73e207 100644 --- a/php/examples/VaasExample/AuthenticationExamples.php +++ b/php/examples/VaasExample/AuthenticationExamples.php @@ -2,18 +2,17 @@ namespace VaasExamples; -use VaasSdk\Authentication\Authenticator; -use VaasSdk\Authentication\GrantType; -use VaasSdk\Options\AuthenticationOptions; +use VaasSdk\Authentication\ClientCredentialsGrantAuthenticator; +use VaasSdk\Sha256; use VaasSdk\Vaas; // If you got a username and password from us, you can use the ResourceOwnerPasswordAuthenticator like this -// $credentials = new AuthenticationOptions( -// grantType: GrantType::PASSWORD, -// clientId: getenv("VAAS_CLIENT_ID"), -// username: getenv("VAAS_USER_NAME"), -// password: getenv("VAAS_PASSWORD") +// $authenticator = new ResourceOwnerPasswordGrantAuthenticator( +// clientId: getenv("CLIENT_ID"), +// username: getenv("USERNAME"), +// password: getenv("PASSWORD"), +// tokenUrl: getenv("TOKEN_URL") // ); // You may use self registration and create a new username and password for the @@ -21,15 +20,16 @@ // If you got a client id and client secret from us, you can use the `Client Credentials` authentication method like this -$credentials = new AuthenticationOptions( - grantType: GrantType::CLIENT_CREDENTIALS, +$authenticator = new ClientCredentialsGrantAuthenticator( clientId: getenv("CLIENT_ID"), - clientSecret: getenv("CLIENT_SECRET") + clientSecret: getenv("CLIENT_SECRET"), + tokenUrl: getenv("TOKEN_URL") ); -$authenticator = new Authenticator($credentials); -$vaas = new Vaas($authenticator); +$vaas = (new Vaas()) + ->withAuthenticator($authenticator) + ->build(); // Get verdict for an eicar hash -$vaasVerdict = $vaas->forSha256Async("000005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8")->await(); +$vaasVerdict = $vaas->forSha256Async(Sha256::TryFromString("000005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8"))->await(); fwrite(STDOUT, "Verdict for $vaasVerdict->sha256 is $vaasVerdict->verdict->value \n"); diff --git a/php/examples/VaasExample/GetVerdictByFile.php b/php/examples/VaasExample/GetVerdictByFile.php index 4efe0650..c804a84a 100644 --- a/php/examples/VaasExample/GetVerdictByFile.php +++ b/php/examples/VaasExample/GetVerdictByFile.php @@ -2,22 +2,22 @@ namespace VaasExamples; -use VaasSdk\Authentication\Authenticator; -use VaasSdk\Authentication\GrantType; -use VaasSdk\Options\AuthenticationOptions; +use VaasSdk\Authentication\ClientCredentialsGrantAuthenticator; use VaasSdk\Vaas; include_once("./vendor/autoload.php"); -$credentials = new AuthenticationOptions( - grantType: GrantType::CLIENT_CREDENTIALS, + +$authenticator = new ClientCredentialsGrantAuthenticator( clientId: getenv("CLIENT_ID"), - clientSecret: getenv("CLIENT_SECRET") + clientSecret: getenv("CLIENT_SECRET"), + tokenUrl: getenv("TOKEN_URL") ); -$authenticator = new Authenticator($credentials); +$vaas = (new Vaas()) + ->withAuthenticator($authenticator) + ->build(); -$vaas = new Vaas($authenticator); $scanPath = getenv("SCAN_PATH"); $vaasVerdict = $vaas->forFileAsync($scanPath)->await(); diff --git a/php/examples/VaasExample/GetVerdictByHash.php b/php/examples/VaasExample/GetVerdictByHash.php index 589a2fd4..773c609d 100644 --- a/php/examples/VaasExample/GetVerdictByHash.php +++ b/php/examples/VaasExample/GetVerdictByHash.php @@ -2,26 +2,29 @@ namespace VaasExamples; -use VaasSdk\Authentication\Authenticator; -use VaasSdk\Authentication\GrantType; -use VaasSdk\Options\AuthenticationOptions; +use VaasSdk\Authentication\ClientCredentialsGrantAuthenticator; +use VaasSdk\Sha256; use VaasSdk\Vaas; include_once("./vendor/autoload.php"); -$credentials = new AuthenticationOptions( - grantType: GrantType::CLIENT_CREDENTIALS, + +$authenticator = new ClientCredentialsGrantAuthenticator( clientId: getenv("CLIENT_ID"), - clientSecret: getenv("CLIENT_SECRET") + clientSecret: getenv("CLIENT_SECRET"), + tokenUrl: getenv("TOKEN_URL") ); -$authenticator = new Authenticator($credentials); +$vaas = (new Vaas()) + ->withAuthenticator($authenticator) + ->build(); -$vaas = new Vaas($authenticator); // EICAR -$vaasVerdict = $vaas->forSha256Async("000005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8")->await(); +$vaasVerdict = $vaas->forSha256Async(Sha256::TryFromString("000005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8"))->await(); fwrite(STDOUT, "Verdict for $vaasVerdict->sha256 is " . $vaasVerdict->verdict->value . " \n"); -// SOMEFILE -$vaasVerdict = $vaas->forSha256Async("70caea443deb0d0a890468f9ac0a9b1187676ba3e66eb60a722b187107eb1ea8")->await(); + + +// Some file +$vaasVerdict = $vaas->forSha256Async(Sha256::TryFromString("70caea443deb0d0a890468f9ac0a9b1187676ba3e66eb60a722b187107eb1ea8"))->await(); fwrite(STDOUT, "Verdict for $vaasVerdict->sha256 is " . $vaasVerdict->verdict->value . " \n"); diff --git a/php/examples/VaasExample/GetVerdictByUrl.php b/php/examples/VaasExample/GetVerdictByUrl.php index 56b2e530..de72076b 100644 --- a/php/examples/VaasExample/GetVerdictByUrl.php +++ b/php/examples/VaasExample/GetVerdictByUrl.php @@ -2,26 +2,27 @@ namespace VaasExamples; -use VaasSdk\Authentication\Authenticator; -use VaasSdk\Authentication\GrantType; -use VaasSdk\Options\AuthenticationOptions; +use VaasSdk\Authentication\ClientCredentialsGrantAuthenticator; use VaasSdk\Vaas; include_once("./vendor/autoload.php"); -$credentials = new AuthenticationOptions( - grantType: GrantType::CLIENT_CREDENTIALS, + +$authenticator = new ClientCredentialsGrantAuthenticator( clientId: getenv("CLIENT_ID"), - clientSecret: getenv("CLIENT_SECRET") + clientSecret: getenv("CLIENT_SECRET"), + tokenUrl: getenv("TOKEN_URL") ); -$authenticator = new Authenticator($credentials); +$vaas = (new Vaas()) + ->withAuthenticator($authenticator) + ->build(); -$vaas = new Vaas($authenticator); // EICAR $vaasVerdict = $vaas->forUrlAsync("https://secure.eicar.org/eicar.com")->await(); fwrite(STDOUT, "Verdict for $vaasVerdict->sha256 is " . $vaasVerdict->verdict->value . " \n"); -// SOMEFILE + +// Some file $vaasVerdict = $vaas->forUrlAsync("https://www.gdatasoftware.com/oem/verdict-as-a-service")->await(); fwrite(STDOUT, "Verdict for $vaasVerdict->sha256 is " . $vaasVerdict->verdict->value . " \n"); diff --git a/php/src/vaas/Authentication/AuthenticatorInterface.php b/php/src/vaas/Authentication/AuthenticatorInterface.php new file mode 100644 index 00000000..7c889df3 --- /dev/null +++ b/php/src/vaas/Authentication/AuthenticatorInterface.php @@ -0,0 +1,11 @@ +tokenReceiver = new TokenReceiver($options, $httpClient); + } + + /** + * Gets the access token asynchronously. + * If the token is still valid, it will be returned immediately. + * If the token is expired, a new token will be requested. + * @param Cancellation|null $cancellation Cancellation token + * @return Future Future that resolves to the access token string + */ + public function getTokenAsync(?Cancellation $cancellation = null): Future + { + return async(function () use ($cancellation) { + return $this->tokenReceiver->getTokenAsync($cancellation)->await(); + }); + } +} \ No newline at end of file diff --git a/php/src/vaas/Authentication/GrantType.php b/php/src/vaas/Authentication/GrantType.php index 4499fcdb..e9e2b745 100644 --- a/php/src/vaas/Authentication/GrantType.php +++ b/php/src/vaas/Authentication/GrantType.php @@ -2,8 +2,8 @@ namespace VaasSdk\Authentication; -class GrantType +enum GrantType: string { - const CLIENT_CREDENTIALS = 'client_credentials'; - const PASSWORD = 'password'; + case CLIENT_CREDENTIALS = 'client_credentials'; + case PASSWORD = 'password'; } \ No newline at end of file diff --git a/php/src/vaas/Authentication/ResourceOwnerPasswordGrantAuthenticator.php b/php/src/vaas/Authentication/ResourceOwnerPasswordGrantAuthenticator.php new file mode 100644 index 00000000..9910bf0a --- /dev/null +++ b/php/src/vaas/Authentication/ResourceOwnerPasswordGrantAuthenticator.php @@ -0,0 +1,49 @@ +tokenReceiver = new TokenReceiver($options, $httpClient); + } + + /** + * Gets the access token asynchronously. + * If the token is still valid, it will be returned immediately. + * If the token is expired, a new token will be requested. + * @param Cancellation|null $cancellation Cancellation token + * @return Future Future that resolves to the access token string + */ + public function getTokenAsync(?Cancellation $cancellation = null): Future + { + return async(function () use ($cancellation) { + return $this->tokenReceiver->getTokenAsync($cancellation)->await(); + }); + } +} \ No newline at end of file diff --git a/php/src/vaas/Authentication/Authenticator.php b/php/src/vaas/Authentication/TokenReceiver.php similarity index 83% rename from php/src/vaas/Authentication/Authenticator.php rename to php/src/vaas/Authentication/TokenReceiver.php index 36977755..2d30b805 100644 --- a/php/src/vaas/Authentication/Authenticator.php +++ b/php/src/vaas/Authentication/TokenReceiver.php @@ -13,24 +13,21 @@ use InvalidArgumentException; use VaasSdk\Exceptions\VaasAuthenticationException; use VaasSdk\Options\AuthenticationOptions; -use VaasSdk\Options\VaasOptions; use function Amp\async; use function Amp\delay; -class Authenticator +class TokenReceiver { private HttpClient $httpClient; - private VaasOptions $options; - private AuthenticationOptions $credentials; + private AuthenticationOptions $authenticationOptions; private Mutex $mutex; private ?TokenResponse $lastTokenResponse = null; private int $validTo = 0; private ?int $lastRequestTime = null; - public function __construct(AuthenticationOptions $credentials, ?VaasOptions $options = null, ?HttpClient $httpClient = null) + public function __construct(AuthenticationOptions $options, ?HttpClient $httpClient = null) { - $this->credentials = $credentials; - $this->options = $options ?? new VaasOptions(); + $this->authenticationOptions = $options; $this->httpClient = $httpClient ?? HttpClientBuilder::buildDefault(); $this->mutex = new LocalMutex(); } @@ -84,7 +81,7 @@ private function requestTokenAsync(?Cancellation $cancellation = null): Future { return async(function () use ($cancellation) { $form = $this->tokenRequestToForm(); - $request = new Request($this->options->tokenUrl, 'POST'); + $request = new Request($this->authenticationOptions->tokenUrl, 'POST'); $request->setBody($form); $request->setHeader('Content-Type', 'application/x-www-form-urlencoded'); @@ -121,18 +118,18 @@ private function requestTokenAsync(?Cancellation $cancellation = null): Future */ private function tokenRequestToForm(): string { - if ($this->credentials->grantType === GrantType::CLIENT_CREDENTIALS) { + if ($this->authenticationOptions->grantType == GrantType::CLIENT_CREDENTIALS) { return http_build_query([ - 'client_id' => $this->credentials->clientId, - 'client_secret' => $this->credentials->clientSecret ?? throw new InvalidArgumentException(), + 'client_id' => $this->authenticationOptions->clientId, + 'client_secret' => $this->authenticationOptions->clientSecret ?? throw new InvalidArgumentException(), 'grant_type' => 'client_credentials', ]); } return http_build_query([ - 'client_id' => $this->credentials->clientId, - 'username' => $this->credentials->userName ?? throw new InvalidArgumentException(), - 'password' => $this->credentials->password ?? throw new InvalidArgumentException(), + 'client_id' => $this->authenticationOptions->clientId, + 'username' => $this->authenticationOptions->userName ?? throw new InvalidArgumentException(), + 'password' => $this->authenticationOptions->password ?? throw new InvalidArgumentException(), 'grant_type' => 'password', ]); } diff --git a/php/src/vaas/Exceptions/FileDoesNotExistException.php b/php/src/vaas/Exceptions/FileDoesNotExistException.php new file mode 100644 index 00000000..93217cfe --- /dev/null +++ b/php/src/vaas/Exceptions/FileDoesNotExistException.php @@ -0,0 +1,13 @@ +grantType = $grantType; - $this->clientId = $clientId; - $this->clientSecret = $clientSecret; - $this->userName = $userName; - $this->password = $password; - $this->validate(); } diff --git a/php/src/vaas/Options/VaasOptions.php b/php/src/vaas/Options/VaasOptions.php index 58addee0..26251208 100644 --- a/php/src/vaas/Options/VaasOptions.php +++ b/php/src/vaas/Options/VaasOptions.php @@ -4,23 +4,17 @@ class VaasOptions { - public ?bool $useHashLookup; - public ?bool $useCache; - public string $url; - public string $tokenUrl; - public ?int $timeout; - + /** + * Options to control the behavior of the VaaS SDK + * @param bool|null $useHashLookup Use the G DATA cloud to check the hash of the file + * @param bool|null $useCache Use the cache to store the hash of the file + * @param string $vaasUrl The URL of the VaaS backend to use either the G DATA cloud or a self-hosted instance + * @param int $timeout The timeout in seconds for the file upload to the VaaS backend + */ public function __construct( - ?bool $useHashLookup = null, - ?bool $useCache = null, - string $url = 'https://gateway.production.vaas.gdatasecurity.de/', - string $tokenUrl = 'https://account.gdata.de/realms/vaas-production/protocol/openid-connect/token', - ?int $timeout = null - ) { - $this->url = $url; - $this->useHashLookup = $useHashLookup; - $this->useCache = $useCache; - $this->tokenUrl = $tokenUrl; - $this->timeout = $timeout; - } + public bool $useHashLookup = true, + public bool $useCache = true, + public string $vaasUrl = 'https://gateway.production.vaas.gdatasecurity.de/', + public int $timeout = 300 + ) {} } \ No newline at end of file diff --git a/php/src/vaas/Sha256.php b/php/src/vaas/Sha256.php new file mode 100644 index 00000000..1c16a27f --- /dev/null +++ b/php/src/vaas/Sha256.php @@ -0,0 +1,70 @@ +_hash = $hashString; + return $sha256; + } + + throw new InvalidSha256Exception(); + } + + /** + * Gets Sha256 from string + * @param string $hashString the string to create the hash from + * @return Sha256 the sha256 hash + * @throws InvalidSha256Exception if the hash is invalid + */ + public static function TryFromString(string $hashString): Sha256 + { + if (Sha256::IsValid($hashString)) { + $sha256 = new Sha256(); + $sha256->_hash = $hashString; + return $sha256; + } + throw new InvalidSha256Exception(); + } + + /** + * Validates a hash to be a valid sha256 + * @param string $hash the string to validate + * @return bool returns true if sha256 is valid + */ + public static function IsValid(string $hash): bool + { + if (preg_match("/^([a-f0-9]{64})$/", strtolower($hash)) == 1) { + return true; + } else { + return false; + } + } + + public function __toString(): string + { + return $this->_hash; + } +} \ No newline at end of file diff --git a/php/src/vaas/Vaas.php b/php/src/vaas/Vaas.php index caff1c7b..81777e42 100644 --- a/php/src/vaas/Vaas.php +++ b/php/src/vaas/Vaas.php @@ -14,7 +14,9 @@ use Amp\Http\Client\Response; use Amp\Http\Client\StreamedContent; use Exception; -use VaasSdk\Authentication\Authenticator; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use VaasSdk\Authentication\AuthenticatorInterface; use VaasSdk\Exceptions\VaasAuthenticationException; use VaasSdk\Exceptions\VaasClientException; use VaasSdk\Exceptions\VaasServerException; @@ -32,46 +34,92 @@ class Vaas private const PRODUCT_VERSION = '0.0.0'; private HttpClient $httpClient; - private Authenticator $authenticator; + private AuthenticatorInterface $authenticator; private VaasOptions $options; + private LoggerInterface $logger; /** - * Create a new Vaas instance - * @param Authenticator $authenticator Authenticator to use for fetching tokens - * @param VaasOptions|null $options Options for the Vaas instance to set usage of cache and hash lookup - * @param HttpClient|null $httpClient HTTP client to use for requests + * Optional parameters for the Vaas client like + * - the URL of the VaaS backend + * - whether to use the cache (default: true) + * - whether to use the G DATA cloud for hash lookups (default: true) + * - the timeout in seconds for the file upload to the VaaS backend (default: 300) + * @param VaasOptions $options Options for the Vaas client + * @return $this */ - public function __construct(Authenticator $authenticator, ?VaasOptions $options = null, ?HttpClient $httpClient = null) + public function withOptions(VaasOptions $options): self + { + $this->options = $options; + return $this; + } + + /** + * @param HttpClient $httpClient Your optional custom http client. + * @return $this + */ + public function withHttpClient(HttpClient $httpClient): self + { + $this->httpClient = $httpClient; + return $this; + } + + /** + * Either use the `ClientCredentialsGrantAuthenticator` or `ResourceOwnerPasswordGrantAuthenticator` + * Use the `ClientCredentialsGrantAuthenticator` if you have a client id and client secret. + * Use the `ResourceOwnerPasswordGrantAuthenticator` if you have a username and password. + * Last one is the choice if you have registered yourself on https://vaas.gdata.de/login. In this case, the client id is `vaas-customer`. + * @param AuthenticatorInterface $authenticator The authenticator to use + * @return $this + */ + public function withAuthenticator(AuthenticatorInterface $authenticator): self { $this->authenticator = $authenticator; - - if ($options === null) { - $this->options = new VaasOptions(); - } else { - $this->options = $options; + return $this; + } + + /** + * Set the logger to use + * @param LoggerInterface $logger The logger to use + * @return $this + */ + public function withLogger(LoggerInterface $logger): self + { + $this->logger = $logger; + return $this; + } + + /** + * Build the Vaas client + * @return $this + * @throws VaasClientException If the authenticator is not set + */ + public function build(): self + { + if (!isset($this->logger)) { + $this->logger = new NullLogger(); + } + if (!isset($this->authenticator)) { + throw new VaasClientException('Authenticator is required'); } - - if ($httpClient === null) { + if (!isset($this->httpClient)) { $this->httpClient = HttpClientBuilder::buildDefault(); - } else { - $this->httpClient = $httpClient; } + if (!isset($this->options)) { + $this->options = new VaasOptions(); + } + return $this; } /** * Get the verdict for a file by its SHA256 hash - * @param string $sha256 The SHA256 hash of the file to check + * @param Sha256 $sha256 The SHA256 hash of the file to check * @param ForSha256Options|null $options Options for the request * @param Cancellation|null $cancellation Cancellation token * @return Future A future that resolves to a VaasVerdict */ - public function forSha256Async(string $sha256, ?ForSha256Options $options = null, ?Cancellation $cancellation = null): Future + public function forSha256Async(Sha256 $sha256, ?ForSha256Options $options = null, ?Cancellation $cancellation = null): Future { - return async(function () use ($sha256, $options, $cancellation) { - if (!preg_match('/^[a-f0-9]{64}$/', $sha256)) { - throw new VaasClientException('Invalid SHA256 hash'); - } - + return async(function () use ($sha256, $options, $cancellation) { if ($options === null) { $options = new ForSha256Options( [ @@ -82,7 +130,7 @@ public function forSha256Async(string $sha256, ?ForSha256Options $options = null ); } $url = sprintf('%s/files/%s/report/?useCache=%s&useHashLookup=%s', - $this->options->url, + $this->options->vaasUrl, $sha256, json_encode($options->useCache), json_encode($options->useHashLookup @@ -90,7 +138,7 @@ public function forSha256Async(string $sha256, ?ForSha256Options $options = null $request = new Request($url, 'GET'); - while (7 + 7 === 14) { + while (true) { $this->addRequestHeadersAsync($request, $options->vaasRequestId)->await($cancellation); $response = $this->httpClient->request($request, $cancellation); @@ -110,8 +158,6 @@ public function forSha256Async(string $sha256, ?ForSha256Options $options = null throw $this->parseVaasError($response); } } - - throw new Exception('This should never happen'); }, $cancellation); } @@ -140,12 +186,12 @@ public function forFileAsync(string $path, ?ForFileOptions $options = null, ?Can } if ($options->useCache || $options->useHashLookup) { - $sha256 = $this->sha256CheckSum($path); $forSha256Options = new ForSha256Options([ 'vaasRequestId' => $options->vaasRequestId, 'useHashLookup' => $options->useHashLookup, 'useCache' => $options->useCache, ]); + $sha256 = Sha256::TryFromFile($path); $response = $this->forSha256Async($sha256, $forSha256Options, $cancellation)->await(); $isVerdictWithoutDetection = ($response->verdict === 'Malicious' || $response->verdict === 'Pup') && !empty($response->detection); if ($response->verdict !== 'Unknown' && !empty($response->fileType) && !empty($response->mimeType) && !$isVerdictWithoutDetection) { @@ -154,6 +200,8 @@ public function forFileAsync(string $path, ?ForFileOptions $options = null, ?Can } $stream = openFile($path, 'r'); + $stream->onClose(fn() => $stream->close()); + $forStreamOptions = new ForStreamOptions([ 'vaasRequestId' => $options->vaasRequestId, 'useHashLookup' => $options->useHashLookup, @@ -179,12 +227,12 @@ public function forStreamAsync(ReadableStream $stream, int $fileSize, ?ForStream $options = new ForStreamOptions( [ 'vaasRequestId' => null, - 'timeout' => $this->options->timeout ?? 300, + 'timeout' => $this->options->timeout, 'useHashLookup' => $this->options->useHashLookup ?? true, ] ); } - $url = sprintf('%s/files?useHashLookup=%s', $this->options->url, json_encode($options->useHashLookup)); + $url = sprintf('%s/files?useHashLookup=%s', $this->options->vaasUrl, json_encode($options->useHashLookup)); $request = new Request($url, 'POST'); @@ -192,6 +240,7 @@ public function forStreamAsync(ReadableStream $stream, int $fileSize, ?ForStream $request->setTransferTimeout($options->timeout); $this->addRequestHeadersAsync($request, $options->vaasRequestId)->await(); $response = $this->httpClient->request($request); + $stream->close(); switch ($response->getStatus()) { case 201: $fileAnalysisStarted = json_decode($response->getBody()->buffer(), true); @@ -210,8 +259,13 @@ public function forStreamAsync(ReadableStream $stream, int $fileSize, ?ForStream 'vaasRequestId' => $options->vaasRequestId, 'useHashLookup' => $options->useHashLookup, ]); - - return $this->forSha256Async($fileAnalysisStarted['sha256'], $forSha256Options)->await(); + + if (!isset($fileAnalysisStarted['sha256'])) { + throw new VaasServerException('Unexpected response from the server'); + } + $sha256 = Sha256::TryFromString($fileAnalysisStarted['sha256']); + + return $this->forSha256Async($sha256, $forSha256Options)->await(); }); } @@ -238,7 +292,7 @@ public function forUrlAsync(string $uri, ?ForUrlOptions $options = null, ?Cancel ] ); } - $urlAnalysisUri = sprintf('%s/urls', $this->options->url); + $urlAnalysisUri = sprintf('%s/urls', $this->options->vaasUrl); $urlAnalysisRequest = new Request($urlAnalysisUri, 'POST'); $urlAnalysisRequest->setBody(json_encode([ @@ -269,8 +323,8 @@ public function forUrlAsync(string $uri, ?ForUrlOptions $options = null, ?Cancel throw new VaasServerException('Unexpected response from the server'); } - while (1 - 8 === -7) { - $reportUri = sprintf('%s/urls/%s/report', $this->options->url, $id); + while (true) { + $reportUri = sprintf('%s/urls/%s/report', $this->options->vaasUrl, $id); $reportRequest = new Request($reportUri, 'GET'); $this->addRequestHeadersAsync($reportRequest, $options->vaasRequestId)->await($cancellation); @@ -287,8 +341,6 @@ public function forUrlAsync(string $uri, ?ForUrlOptions $options = null, ?Cancel throw $this->parseVaasError($reportResponse); } } - - throw new Exception('This should never happen'); }, $cancellation); } @@ -347,19 +399,4 @@ private function parseVaasError(Response $response): Exception } } } - - /** - * Calculate the SHA256 hash of a file - * @param string $filePath Path to the file - * @return string SHA256 hash of the file - * @throws VaasClientException If the hash could not be calculated - */ - private function sha256CheckSum(string $filePath): string - { - $hash = hash_file('sha256', $filePath); - if ($hash === false) { - throw new VaasClientException('Could not calculate SHA256 hash'); - } - return $hash; - } } \ No newline at end of file diff --git a/php/tests/vaas/AuthenticatorTest.php b/php/tests/vaas/AuthenticatorTest.php index 462c22c1..64bb56ea 100644 --- a/php/tests/vaas/AuthenticatorTest.php +++ b/php/tests/vaas/AuthenticatorTest.php @@ -5,11 +5,9 @@ use Dotenv\Dotenv; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; -use VaasSdk\Authentication\Authenticator; -use VaasSdk\Authentication\GrantType; +use VaasSdk\Authentication\ClientCredentialsGrantAuthenticator; +use VaasSdk\Authentication\ResourceOwnerPasswordGrantAuthenticator; use VaasSdk\Exceptions\VaasAuthenticationException; -use VaasSdk\Options\AuthenticationOptions; -use VaasSdk\Options\VaasOptions; final class AuthenticatorTest extends TestCase { @@ -50,67 +48,51 @@ public function setUp(): void $this->assertNotNull($_ENV["VAAS_CLIENT_ID"]); } - public function testAuthenticatorWithInvalidClientCredentials_ThrowsAccessDeniedException(): void + public function testClientCredentialsGrantAuthenticator_withInvalidCredentials_ThrowsAccessDeniedException(): void { $this->expectException(VaasAuthenticationException::class); - $credentials = new AuthenticationOptions( - grantType: GrantType::CLIENT_CREDENTIALS, + $authenticator = new ClientCredentialsGrantAuthenticator( clientId: "invalid", clientSecret: "invalid" ); - $authenticator = new Authenticator($credentials); $authenticator->getTokenAsync()->await(); } - public function testAuthenticatorWithInvalidPassword_ThrowsAccessDeniedException(): void + public function testResourceOwnerPasswordGrantAuthenticator_withInvalidCredentials_ThrowsAccessDeniedException(): void { $this->expectException(VaasAuthenticationException::class); - $credentials = new AuthenticationOptions( - GrantType::PASSWORD, + $authenticator = new ResourceOwnerPasswordGrantAuthenticator( clientId: "invalid", userName: "invalid", password: "invalid" ); - $authenticator = new Authenticator($credentials); $authenticator->getTokenAsync()->await(); } - public function testAuthenticatorWithValidClientCredentials_ReturnsToken(): void + public function testClientCredentialsGrantAuthenticator_withValidCredentials_ReturnsToken(): void { - $credentials = new AuthenticationOptions( - grantType: GrantType::CLIENT_CREDENTIALS, + $authenticator = new ClientCredentialsGrantAuthenticator( clientId: $_ENV["CLIENT_ID"], - clientSecret: $_ENV["CLIENT_SECRET"] - ); - - $options = new VaasOptions( - url: $_ENV["VAAS_URL"], + clientSecret: $_ENV["CLIENT_SECRET"], tokenUrl: $_ENV["TOKEN_URL"] ); - - $authenticator = new Authenticator($credentials, $options); + $token = $authenticator->getTokenAsync()->await(); $this->assertNotNull($token); } - public function testAuthenticatorWithValidPassword_ReturnsToken(): void + public function testResourceOwnerPasswordGrantAuthenticator_withValidCredentials_ReturnsToken(): void { - $credentials = new AuthenticationOptions( - grantType: GrantType::PASSWORD, + $authenticator = new ResourceOwnerPasswordGrantAuthenticator( clientId: $_ENV["VAAS_CLIENT_ID"], userName: $_ENV["VAAS_USER_NAME"], - password: $_ENV["VAAS_PASSWORD"] - ); - - $options = new VaasOptions( - url: $_ENV["VAAS_URL"], + password: $_ENV["VAAS_PASSWORD"], tokenUrl: $_ENV["TOKEN_URL"] ); - $authenticator = new Authenticator($credentials, $options); $token = $authenticator->getTokenAsync()->await(); $this->assertNotNull($token); diff --git a/php/tests/vaas/Sha256Test.php b/php/tests/vaas/Sha256Test.php new file mode 100644 index 00000000..6c8e96ee --- /dev/null +++ b/php/tests/vaas/Sha256Test.php @@ -0,0 +1,48 @@ +assertTrue(Sha256::IsValid(Sha256Test::VALID_SHA256)); + } + + public function testIsValidGetsInvalidSha256ReturnsFalse(): void + { + $this->assertFalse(Sha256::IsValid("00005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8")); + } + + public function testTryFromStringGetsValidSha256ReturnsCorrectSha256(): void + { + $calculatedSha256 = Sha256::TryFromString(Sha256Test::VALID_SHA256); + $this->assertEquals(Sha256Test::VALID_SHA256, $calculatedSha256); + } + + public function testTryFromStringGetsInvalidSha256ThrowsInvalidSha256Exception(): void + { + $this->expectException(InvalidSha256Exception::class); + Sha256::TryFromString("00005c43196142f01d615a67b7da8a53cb0172f8e9317a2ec9a0a39a1da6fe8"); + } + + public function testTryFromFileGetsValidSha256ReturnsTrue(): void + { + $calculatedSha256 = Sha256::TryFromFile(Sha256Test::VALID_FILE); + $this->assertEquals(Sha256Test::VALID_SHA256, $calculatedSha256); + } + + public function testTryFromFileGetsInvalidPathThrowsFileDoesNotExistException(): void + { + $this->expectException(FileDoesNotExistException::class); + Sha256::TryFromFile("./filedoesnotexist"); + } +} \ No newline at end of file diff --git a/php/tests/vaas/VaasTest.php b/php/tests/vaas/VaasTest.php index 06bbb744..a407be60 100644 --- a/php/tests/vaas/VaasTest.php +++ b/php/tests/vaas/VaasTest.php @@ -6,11 +6,11 @@ use Dotenv\Dotenv; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; -use VaasSdk\Authentication\Authenticator; -use VaasSdk\Authentication\GrantType; +use VaasSdk\Authentication\ClientCredentialsGrantAuthenticator; +use VaasSdk\Exceptions\InvalidSha256Exception; use VaasSdk\Exceptions\VaasClientException; -use VaasSdk\Options\AuthenticationOptions; use VaasSdk\Options\VaasOptions; +use VaasSdk\Sha256; use VaasSdk\Vaas; use VaasSdk\Verdict; use function Amp\File\openFile; @@ -58,27 +58,27 @@ public function setUp(): void private function getVaas(bool $useCache = false, bool $useHashLookup = true): Vaas { - $credentials = new AuthenticationOptions( - GrantType::CLIENT_CREDENTIALS, - $_ENV["CLIENT_ID"], - $_ENV["CLIENT_SECRET"] + $options = new VaasOptions( + useHashLookup: $useHashLookup, + useCache: $useCache, + vaasUrl: $_ENV["VAAS_URL"] ); - $options = new VaasOptions( - $useHashLookup, - $useCache, - $_ENV["VAAS_URL"], + $authenticator = new ClientCredentialsGrantAuthenticator( + $_ENV["CLIENT_ID"], + $_ENV["CLIENT_SECRET"], $_ENV["TOKEN_URL"] ); - $authenticator = new Authenticator($credentials, $options); - - return new Vaas($authenticator, $options); + return (new Vaas()) + ->withAuthenticator($authenticator) + ->withOptions($options) + ->build(); } public function testForSha256_WithMaliciousSha256_GetsMaliciousResponse(): void { - $verdict = $this->vaas->forSha256Async(self::MALICIOUS_HASH)->await(); + $verdict = $this->vaas->forSha256Async(Sha256::TryFromString(self::MALICIOUS_HASH))->await(); $this->assertEquals(Verdict::MALICIOUS, $verdict->verdict); $this->assertEqualsIgnoringCase(self::MALICIOUS_HASH, $verdict->sha256); @@ -86,36 +86,36 @@ public function testForSha256_WithMaliciousSha256_GetsMaliciousResponse(): void public function testForSha256_WithPupSha256_GetsPupResponse(): void { - $verdict = $this->vaas->forSha256Async(self::PUP_HASH)->await(); - - $this->assertEquals(Verdict::PUP, $verdict->verdict); + $verdict = $this->vaas->forSha256Async(Sha256::TryFromString(self::PUP_HASH))->await(); + $this->assertEqualsIgnoringCase(self::PUP_HASH, $verdict->sha256); + $this->assertEquals(Verdict::PUP, $verdict->verdict); } public function testForSha256_WithCleanSha256_GetsCleanResponse(): void { - $verdict = $this->vaas->forSha256Async(self::CLEAN_HASH)->await(); - - $this->assertEquals(Verdict::CLEAN, $verdict->verdict); + $verdict = $this->vaas->forSha256Async(Sha256::TryFromString(self::CLEAN_HASH))->await(); + $this->assertEqualsIgnoringCase(self::CLEAN_HASH, $verdict->sha256); + $this->assertEquals(Verdict::CLEAN, $verdict->verdict); } public function testForSha256_WithUnknownSha256_GetsUnknownResponse(): void { $vaas = $this->getVaas(false, false); - $verdict = $vaas->forSha256Async(self::UNKNOWN_HASH)->await(); - - $this->assertEquals(Verdict::UNKNOWN, $verdict->verdict); + $verdict = $vaas->forSha256Async(Sha256::TryFromString(self::UNKNOWN_HASH))->await(); + $this->assertEqualsIgnoringCase(self::UNKNOWN_HASH, $verdict->sha256); + $this->assertEquals(Verdict::UNKNOWN, $verdict->verdict); } - public function testForSha256_WithInvalidSha256_ThrowsVaasClientException(): void + public function testForSha256_WithInvalidSha256_ThrowsInvalidSha256Exception(): void { - $this->expectException(VaasClientException::class); + $this->expectException(InvalidSha256Exception::class); $this->expectExceptionMessage("Invalid SHA256 hash"); - $this->vaas->forSha256Async("invalid")->await(); + $this->vaas->forSha256Async(Sha256::TryFromString("invalid"))->await(); } public function testForUrl_WithMaliciousUrl_GetsMaliciousResponse(): void diff --git a/php/tests/vaas/testfile b/php/tests/vaas/testfile new file mode 100644 index 00000000..d724ac08 --- /dev/null +++ b/php/tests/vaas/testfile @@ -0,0 +1 @@ +dsfasdfsd \ No newline at end of file