Files
alfa-bank-sdk/src/Traits/SignableData.php
Anatoliy Poloz a05a6506e8 fix(sign)
2026-03-21 07:10:16 +03:00

59 lines
1.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Apoloz\AlfaBank\Traits;
use Apoloz\AlfaBank\Contracts\SignerInterface;
use Apoloz\AlfaBank\Data\NominalAccounts\Payouts\DigestSignatureData;
use Spatie\LaravelData\DataCollection;
trait SignableData
{
public function sign(SignerInterface $signer): self
{
// 1. Get raw data as array
$data = $this->toArray();
// 2. Remove existing signatures if any
unset($data['digestSignatures']);
// 3. Canonicalize (RFC 8785 - simple version: sort keys, remove nulls, no spaces)
$canonicalData = $this->canonicalizeArray($data);
$jsonToSign = json_encode($canonicalData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
// 4. Sign
$signature = $signer->sign($jsonToSign);
// 5. Attach signature to the original object
if ($this->digestSignatures === null) {
$this->digestSignatures = new DataCollection(DigestSignatureData::class, []);
}
$current = array_values($this->digestSignatures->toCollection()->all());
$current[] = new DigestSignatureData($signature, 'RSA');
$this->digestSignatures = new DataCollection(DigestSignatureData::class, $current);
return $this;
}
private function canonicalizeArray(array $array): array
{
// Remove nulls and empty strings
$array = array_filter($array, fn ($v) => $v !== null);
// Sort keys lexically
ksort($array);
foreach ($array as $key => $value) {
if (is_array($value)) {
$array[$key] = $this->canonicalizeArray($value);
}
}
return $array;
}
}