97 lines
3.4 KiB
PHP
97 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Esun\MultiLocaleTranslation\Model\Google;
|
|
|
|
use Magento\Framework\App\CacheInterface;
|
|
use Magento\Framework\Exception\LocalizedException;
|
|
use Magento\Framework\HTTP\Client\CurlFactory;
|
|
|
|
class AccessToken
|
|
{
|
|
private const TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
private const SCOPE = 'https://www.googleapis.com/auth/cloud-translation';
|
|
private const CACHE_PREFIX = 'ESUN_GOOGLE_TRANSLATION_TOKEN_';
|
|
|
|
public function __construct(
|
|
private readonly Credentials $credentials,
|
|
private readonly CurlFactory $curlFactory,
|
|
private readonly CacheInterface $cache
|
|
) {
|
|
}
|
|
|
|
public function get(): string
|
|
{
|
|
$credentials = $this->credentials->get();
|
|
$cacheKey = self::CACHE_PREFIX . strtoupper(hash('sha256', $credentials['client_email']));
|
|
$cached = (string)$this->cache->load($cacheKey);
|
|
if ($cached !== '') {
|
|
return $cached;
|
|
}
|
|
|
|
$now = time();
|
|
$header = ['alg' => 'RS256', 'typ' => 'JWT'];
|
|
if (!empty($credentials['private_key_id'])) {
|
|
$header['kid'] = $credentials['private_key_id'];
|
|
}
|
|
$claims = [
|
|
'iss' => $credentials['client_email'],
|
|
'scope' => self::SCOPE,
|
|
'aud' => self::TOKEN_URL,
|
|
'iat' => $now,
|
|
'exp' => $now + 3600,
|
|
];
|
|
|
|
$unsignedJwt = $this->base64UrlEncode($this->encodeJson($header))
|
|
. '.' . $this->base64UrlEncode($this->encodeJson($claims));
|
|
$privateKey = openssl_pkey_get_private($credentials['private_key']);
|
|
$signature = '';
|
|
if ($privateKey === false
|
|
|| !openssl_sign($unsignedJwt, $signature, $privateKey, OPENSSL_ALGO_SHA256)
|
|
) {
|
|
throw new LocalizedException(__('Unable to sign the Google service account request.'));
|
|
}
|
|
|
|
$assertion = $unsignedJwt . '.' . $this->base64UrlEncode($signature);
|
|
$client = $this->curlFactory->create();
|
|
$client->setTimeout(30);
|
|
$client->setHeaders(['Content-Type' => 'application/x-www-form-urlencoded']);
|
|
$client->post(self::TOKEN_URL, http_build_query([
|
|
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
'assertion' => $assertion,
|
|
], '', '&', PHP_QUERY_RFC3986));
|
|
|
|
$response = json_decode((string)$client->getBody(), true);
|
|
$token = is_array($response) ? (string)($response['access_token'] ?? '') : '';
|
|
if ($client->getStatus() < 200 || $client->getStatus() >= 300 || $token === '') {
|
|
$message = is_array($response)
|
|
? (string)($response['error_description'] ?? $response['error'] ?? '')
|
|
: '';
|
|
throw new LocalizedException(
|
|
__('Google service account authentication failed (HTTP %1): %2',
|
|
$client->getStatus(),
|
|
$message ?: 'Unknown error')
|
|
);
|
|
}
|
|
|
|
$lifetime = max(60, min(3300, (int)($response['expires_in'] ?? 3600) - 300));
|
|
$this->cache->save($token, $cacheKey, [], $lifetime);
|
|
|
|
return $token;
|
|
}
|
|
|
|
private function base64UrlEncode(string $value): string
|
|
{
|
|
return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
|
|
}
|
|
|
|
private function encodeJson(array $value): string
|
|
{
|
|
return json_encode(
|
|
$value,
|
|
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR
|
|
);
|
|
}
|
|
}
|