Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 46 additions & 37 deletions src/Services/InfoProviderSystem/Providers/TMEClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,74 +24,83 @@
namespace App\Services\InfoProviderSystem\Providers;

use App\Settings\InfoProviderSystem\TMESettings;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;

class TMEClient
{
public const BASE_URI = 'https://api.tme.eu';

public function __construct(private readonly HttpClientInterface $tmeClient, private readonly TMESettings $settings)
public function __construct(
private readonly HttpClientInterface $tmeClient,
private readonly TMESettings $settings,
#[Autowire(service: 'info_provider.cache')]
private readonly CacheInterface $cache
)
{

}

public function makeRequest(string $action, array $parameters): ResponseInterface
/*
* Make a request to the TME API.
* Transparently handles session token generation and renewal.
* @return bool true if the client is usable
*/
public function makeRequest(string $endpoint, array $parameters): ResponseInterface
{
$parameters['Token'] = $this->settings->apiToken;
$parameters['ApiSignature'] = $this->getSignature($action, $parameters, $this->settings->apiSecret);
$session_token = $this->getSessionToken();

return $this->tmeClient->request('POST', $this->getUrlForAction($action), [
'body' => $parameters,
return $this->tmeClient->request('GET', $this->getUrlForEndpoint($endpoint), [
'headers' => [
'Authorization' => 'Bearer ' . $session_token
],
'query' => $parameters
]);
}

/*
* Checks if the current settings allow the client to be used.
* @return bool true if the client is usable
*/
public function isUsable(): bool
{
return !($this->settings->apiToken === null || $this->settings->apiSecret === null);
}

/**
* Returns true if the client is using a private (account related token) instead of a deprecated anonymous token
* to authenticate with TME.
* @return bool
*/
public function isUsingPrivateToken(): bool
private function getUrlForEndpoint(string $endpoint): string
{
//Private tokens are longer than anonymous ones (50 instead of 45 characters)
return strlen($this->settings->apiToken ?? '') > 45;
return self::BASE_URI . '/' . ltrim($endpoint, '/');
}

/**
* Generates the signature for the given action and parameters.
* Taken from https://github.com/tme-dev/TME-API/blob/master/PHP/basic/using_curl.php
/*
* Gets the session token from the local cache, or requests a new one if it is nonexistent
* or expired.
* @return string valid session token
*/
public function getSignature(string $action, array $parameters, string $appSecret): string
private function getSessionToken(): string
{
$parameters = $this->sortSignatureParams($parameters);
return $this->cache->get($this->getTokenCacheKey(), function (ItemInterface $item): string {

$queryString = http_build_query($parameters, '', '&', PHP_QUERY_RFC3986);
$signatureBase = strtoupper('POST') .
'&' . rawurlencode($this->getUrlForAction($action)) . '&' . rawurlencode($queryString);
// Request new session from the API
$response = $this->tmeClient->request('POST', $this->getUrlForEndpoint('/auth/token'), [
'auth_basic' => [$this->settings->apiToken, $this->settings->apiSecret],
'body' => ['grant_type' => 'client_credentials'],
]);

return base64_encode(hash_hmac('sha1', $signatureBase, $appSecret, true));
}
$data = $response->toArray();

private function getUrlForAction(string $action): string
{
return self::BASE_URI . '/' . $action . '.json';
// Subtract 30s as a safety buffer
$item->expiresAfter($data['expires_in'] - 30);

return $data['access_token'];
});
}

private function sortSignatureParams(array $params): array
private function getTokenCacheKey(): string
{
ksort($params);

foreach ($params as &$value) {
if (is_array($value)) {
$value = $this->sortSignatureParams($value);
}
}

return $params;
return 'tme_api_v2_token_' . hash('xxh3', $this->settings->apiToken . $this->settings->apiSecret);
}
}
Loading