HMAC implementation for signature validation

This commit is contained in:
Juan Pablo Vial
2025-06-03 21:53:49 -04:00
parent 8c0bd450ef
commit 981858f251
3 changed files with 39 additions and 8 deletions

View File

@ -45,7 +45,8 @@ return [
'/api/external' => [
'/toku/success' => [
'validator' => Incoviba\Service\Venta\MediosPago\Toku::class,
'token' => $container->get('TOKU_TOKEN')
'token' => $container->get('TOKU_TOKEN'),
'secret' => $container->get('TOKU_WEBHOOK_SECRET'),
]
],
]

17
app/src/Service/HMAC.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace Incoviba\Service;
use Incoviba\Common\Ideal;
class HMAC extends Ideal\Service
{
public static function validate(string $timestamp, string $requestSignature, string $requestId, string $secret): bool
{
$message = "{$timestamp}.{$requestId}";
$encodedSecret = mb_convert_encoding($secret, 'UTF-8');
$encodedMessage = mb_convert_encoding($message, 'UTF-8');
$hmacObject = hash_hmac('sha256', $encodedMessage, $encodedSecret);
$computedSignature = base64_encode($hmacObject);
return hash_equals($computedSignature, $requestSignature);
}
}

View File

@ -1,6 +1,7 @@
<?php
namespace Incoviba\Service\Venta\MediosPago;
use Incoviba\Service\HMAC;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Incoviba\Service\Venta\MediosPago\Toku\{Customer,Subscription,Invoice};
@ -11,6 +12,7 @@ use Incoviba\Exception\ServiceAction\Read;
use Incoviba\Model;
use Incoviba\Model\Persona;
use Incoviba\Model\Venta\Propietario;
use Throwable;
class Toku extends Ideal\Service
{
@ -407,12 +409,23 @@ class Toku extends Ideal\Service
return false;
}
$tracestate = explode(';', substr($request->getHeaderLine('Tracestate'), strlen('dd=')));
$ptid = substr(array_find($tracestate, fn($item) => str_starts_with($item, 't.tid:')), strlen('t.tid:'));
$datadogTags = explode(',', $request->getHeaderLine('X-Datadog-Tags'));
$tid = array_find($datadogTags, fn($item) => str_contains($item, 'p.tid='));
$tid = substr($tid, strpos($tid, 'p.tid=') + strlen('p.tid='));
return $tid === $ptid;
$tokuSignature = $request->getHeaderLine('Toku-Signature');
try {
list($timestamp, $signature) = array_map(function($elem) {
return explode('=', $elem)[1];
}, explode(',', $tokuSignature));
$body = $request->getBody()->getContents();
$json = json_decode($body, true);
if (!is_array($json)) {
return false;
}
if (!array_key_exists('id', $json)) {
return false;
}
$eventId = $json['id'];
return HMAC::validate($timestamp, $signature, $eventId, $tokenConfig['secret']);
} catch (Throwable $throwable) {
return false;
}
}
}