docusign_signature-1.0.x-dev/src/Services/HmacSecurity.php
src/Services/HmacSecurity.php
<?php
declare(strict_types=1);
namespace Drupal\docusign_signature\Services;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Manage HMAC security.
*
* @package Drupal\docusign_signature\Services
*/
class HmacSecurity {
/**
* The DocuSign signature key prefix.
* A same request may contain serveral header with an iterated suffix.
*
* @var string
*/
const SIGNATURE_KEY_PREFIX = 'XDocusignSignature';
/**
* DocuSign module configuration.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
private ImmutableConfig $config;
/**
* Current request.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
private Request $request;
/**
* Constructs a new HMAC security object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
*/
public function __construct(ConfigFactoryInterface $config_factory, RequestStack $request_stack) {
$this->config = $config_factory->get('docusign_signature.settings');
$this->request = $request_stack->getCurrentRequest();
}
/**
* Check HMAC Security in request headers.
*
* @param string $payload
* The request payload.
*
* @return bool
* Return "true" if header is present and HMAC is valid.
*/
public function checkRequestHeaders(string $payload): bool {
foreach ($this->request->headers->all() as $key => $value) {
if (
strstr($key, self::SIGNATURE_KEY_PREFIX) &&
$this->isValidSignature($value, $payload)
) {
return TRUE;
}
}
return FALSE;
}
/**
* Compute hash from request payload.
*
* @param string $payload
* The request payload.
*
* @return string
* The expected computed hash.
*/
private function computeHash(string $payload): string {
$hexHash = hash_hmac(
'sha256',
$payload,
$this->config->get('hash.secret')
);
return base64_encode(hex2bin($hexHash));
}
/**
* Check if signature is valid.
*
* @param string $signature
* The request header signature.
* @param string $payload
* The request payload.
*
* @return bool
* Return "true" if HMAC is valid.
*/
private function isValidSignature(string $signature, string $payload): bool {
return hash_equals($signature, $this->computeHash($payload));
}
}
