update macgirvin/http-message-signer to version 2.0

This commit is contained in:
Mario Vavti
2025-07-06 22:58:09 +02:00
parent d396043faf
commit 3014ae2071
8 changed files with 66 additions and 54 deletions

View File

@@ -57,7 +57,7 @@
"mmccook/php-json-canonicalization-scheme": "^1.0",
"scssphp/scssphp": "^2.0.1",
"twbs/bootstrap-icons": "^1.11",
"macgirvin/http-message-signer": "^0.1.6"
"macgirvin/http-message-signer": "^0.2"
},
"require-dev": {
"ext-yaml": "*",

14
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "8f1b58d772a2f4032a722d009de51fc4",
"content-hash": "e409f2a3604db3b1f0476749521bca59",
"packages": [
{
"name": "bakame/http-structured-fields",
@@ -1081,16 +1081,16 @@
},
{
"name": "macgirvin/http-message-signer",
"version": "v0.1.7",
"version": "v0.2.0",
"source": {
"type": "git",
"url": "https://github.com/macgirvin/HTTP-Message-Signer.git",
"reference": "44db674fb750b4e4909cf1aeb3a18a4c68d938ca"
"reference": "055198699858f8a99acf75b62190d70ac0c8cb00"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/macgirvin/HTTP-Message-Signer/zipball/44db674fb750b4e4909cf1aeb3a18a4c68d938ca",
"reference": "44db674fb750b4e4909cf1aeb3a18a4c68d938ca",
"url": "https://api.github.com/repos/macgirvin/HTTP-Message-Signer/zipball/055198699858f8a99acf75b62190d70ac0c8cb00",
"reference": "055198699858f8a99acf75b62190d70ac0c8cb00",
"shasum": ""
},
"require": {
@@ -1116,9 +1116,9 @@
"description": "RFC 9421 HTTP Message Signer and Verifier for PSR-7 requests",
"support": {
"issues": "https://github.com/macgirvin/HTTP-Message-Signer/issues",
"source": "https://github.com/macgirvin/HTTP-Message-Signer/tree/v0.1.7"
"source": "https://github.com/macgirvin/HTTP-Message-Signer/tree/v0.2.0"
},
"time": "2025-06-25T03:19:43+00:00"
"time": "2025-07-01T02:57:39+00:00"
},
{
"name": "michelf/php-markdown",

View File

@@ -339,6 +339,7 @@ return array(
'HTMLPurifier_Zipper' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
'HttpSignature\\HttpMessageSigner' => $vendorDir . '/macgirvin/http-message-signer/src/HttpMessageSigner.php',
'HttpSignature\\StructuredFieldTypes' => $vendorDir . '/macgirvin/http-message-signer/src/StructuredFieldTypes.php',
'HttpSignature\\UnProcessableSignatureException' => $vendorDir . '/macgirvin/http-message-signer/src/UnProcessableSignatureException.php',
'ID3Parser\\ID3Parser' => $vendorDir . '/lukasreschke/id3parser/src/ID3Parser.php',
'ID3Parser\\getID3\\Tags\\getid3_id3v1' => $vendorDir . '/lukasreschke/id3parser/src/getID3/Tags/getid3_id3v1.php',
'ID3Parser\\getID3\\Tags\\getid3_id3v2' => $vendorDir . '/lukasreschke/id3parser/src/getID3/Tags/getid3_id3v2.php',

View File

@@ -645,6 +645,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
'HTMLPurifier_Zipper' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
'HttpSignature\\HttpMessageSigner' => __DIR__ . '/..' . '/macgirvin/http-message-signer/src/HttpMessageSigner.php',
'HttpSignature\\StructuredFieldTypes' => __DIR__ . '/..' . '/macgirvin/http-message-signer/src/StructuredFieldTypes.php',
'HttpSignature\\UnProcessableSignatureException' => __DIR__ . '/..' . '/macgirvin/http-message-signer/src/UnProcessableSignatureException.php',
'ID3Parser\\ID3Parser' => __DIR__ . '/..' . '/lukasreschke/id3parser/src/ID3Parser.php',
'ID3Parser\\getID3\\Tags\\getid3_id3v1' => __DIR__ . '/..' . '/lukasreschke/id3parser/src/getID3/Tags/getid3_id3v1.php',
'ID3Parser\\getID3\\Tags\\getid3_id3v2' => __DIR__ . '/..' . '/lukasreschke/id3parser/src/getID3/Tags/getid3_id3v2.php',

View File

@@ -1112,17 +1112,17 @@
},
{
"name": "macgirvin/http-message-signer",
"version": "v0.1.7",
"version_normalized": "0.1.7.0",
"version": "v0.2.0",
"version_normalized": "0.2.0.0",
"source": {
"type": "git",
"url": "https://github.com/macgirvin/HTTP-Message-Signer.git",
"reference": "44db674fb750b4e4909cf1aeb3a18a4c68d938ca"
"reference": "055198699858f8a99acf75b62190d70ac0c8cb00"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/macgirvin/HTTP-Message-Signer/zipball/44db674fb750b4e4909cf1aeb3a18a4c68d938ca",
"reference": "44db674fb750b4e4909cf1aeb3a18a4c68d938ca",
"url": "https://api.github.com/repos/macgirvin/HTTP-Message-Signer/zipball/055198699858f8a99acf75b62190d70ac0c8cb00",
"reference": "055198699858f8a99acf75b62190d70ac0c8cb00",
"shasum": ""
},
"require": {
@@ -1135,7 +1135,7 @@
"require-dev": {
"phpunit/phpunit": "^10.0"
},
"time": "2025-06-25T03:19:43+00:00",
"time": "2025-07-01T02:57:39+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -1150,7 +1150,7 @@
"description": "RFC 9421 HTTP Message Signer and Verifier for PSR-7 requests",
"support": {
"issues": "https://github.com/macgirvin/HTTP-Message-Signer/issues",
"source": "https://github.com/macgirvin/HTTP-Message-Signer/tree/v0.1.7"
"source": "https://github.com/macgirvin/HTTP-Message-Signer/tree/v0.2.0"
},
"install-path": "../macgirvin/http-message-signer"
},

View File

@@ -3,7 +3,7 @@
'name' => 'zotlabs/hubzilla',
'pretty_version' => 'dev-10.4RC',
'version' => 'dev-10.4RC',
'reference' => '9a3735cd37cfbcd5bc4fefc1282b3cdaf07dc939',
'reference' => 'd396043faf7ec56e3362f07f3bea9d804485d36f',
'type' => 'application',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -146,9 +146,9 @@
'dev_requirement' => false,
),
'macgirvin/http-message-signer' => array(
'pretty_version' => 'v0.1.7',
'version' => '0.1.7.0',
'reference' => '44db674fb750b4e4909cf1aeb3a18a4c68d938ca',
'pretty_version' => 'v0.2.0',
'version' => '0.2.0.0',
'reference' => '055198699858f8a99acf75b62190d70ac0c8cb00',
'type' => 'library',
'install_path' => __DIR__ . '/../macgirvin/http-message-signer',
'aliases' => array(),
@@ -478,7 +478,7 @@
'zotlabs/hubzilla' => array(
'pretty_version' => 'dev-10.4RC',
'version' => 'dev-10.4RC',
'reference' => '9a3735cd37cfbcd5bc4fefc1282b3cdaf07dc939',
'reference' => 'd396043faf7ec56e3362f07f3bea9d804485d36f',
'type' => 'application',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),

View File

@@ -48,6 +48,7 @@ To sign a message, install the composer package guzzlehttp/psr7 and create an in
```php
use HttpSignature\HttpMessageSigner;
use HttpSignature\UnProcessableSignatureException;
use GuzzleHttp\Psr7\Request;
$request = new Request(
@@ -71,9 +72,18 @@ $signer = (new HttpMessageSigner())
->setTag('fediverse') // optional app profile name
->setSignatureId('sig1') // optional, default is sig1
$request = $signer->signRequest('("@method" "@path" "host" "date")', $request);
$isValid = $signer->verifyRequest($request);
try {
$request = $signer->signRequest('("@method" "@path" "host" "date")', $request);
}
catch (UnProcessableSignatureException $exception) {
$whatHappened = $exception->getMessage();
}
try {
$isValid = $signer->verifyRequest($request);
} catch (UnProcessableSignatureException $exception) {
$isValid = false;
$whatHappened = $exception->getMessage();
}
```
See full examples in `/tests`.
@@ -95,12 +105,11 @@ and may include modifier parameters. These are represented as
'("@query-param";name="foo" "header2";sf "header3" ...)'
```
Parameters beginning with '@' are components derived from the HTTP request but may not be represented in the headers. Please review RFC9421 for precise definitions.
Field names beginning with '@' are components derived from the HTTP request but may not be represented in the headers. Please review RFC9421 for precise definitions.
Using the 'sf' parameter on a component will treat a signature component as a Structured Field when normalising the string.
However, parsing Structured Fields by adding the 'sf' parameter is likely to fail unless you know what `type` it is. A built-in table contains the type definition for a number of known stuctured header types. This list is probably incomplete. A method `addStructuredFieldTypes()` is available to add the type information so it can be successfullly parsed. This takes an array with key of the lowercase header name and a value; which is one of 'list', 'innerlist', 'parameters, 'dictionary', 'item'. If the header name is in the list and the 'sf' modifier is used, the header will be parsed as the Structured Field type indicated.
However, parsing Structured Fields by adding the 'sf' parameter is likely to fail unless you know what `type` it is. A built-in table contains the type definition for a number of known stuctured header types. This list is probably incomplete. A method `addStructuredFieldTypes()` is available to add the type information so it can be successfully parsed. This takes an array with key of the lowercase header name and a value; which is one of 'list', 'innerlist', 'parameters, 'dictionary', 'item'. If the header name is in the list and the 'sf' modifier is used, the header will be parsed as the Structured Field type indicated.
If a Structured Field is declared as type 'dictionary'; it is suitable for use with the RFC9421 `key` parameter. Using this parameter will fail if the Structured Field type is unknown or has not been registered.

View File

@@ -136,10 +136,10 @@ class HttpMessageSigner
foreach ($indices as $index) {
$member = $dict->getByIndex($index);
if (!$member) {
throw new \Exception('Index ' . $index . ' not found');
throw new UnProcessableSignatureException('Index ' . $index . ' not found');
}
if (in_array($member, $processedComponents, true)) {
throw new \Exception('Duplicate member found');
throw new UnProcessableSignatureException('Duplicate member found');
}
$processedComponents[] = $member;
$signatureComponents[] = $this->canonicalizeComponent($member, $headers, $interface);
@@ -186,10 +186,10 @@ class HttpMessageSigner
foreach ($indices as $index) {
$member = $dict->getByIndex($index);
if (!$member) {
throw new \Exception('Index ' . $index . ' not found');
throw new UnProcessableSignatureException('Index ' . $index . ' not found');
}
if (in_array($member, $processedComponents, true)) {
throw new \Exception('Duplicate member found');
throw new UnProcessableSignatureException('Duplicate member found');
}
$processedComponents[] = $member;
$signatureComponents[] = $this->canonicalizeComponent($member, $headers, $interface);
@@ -239,7 +239,13 @@ class HttpMessageSigner
$signatureComponents[$dictName][] = $this->canonicalizeComponent($member, $headers, $interface);
}
$parameters = $this->extractParameters($members);
if ($parameters) {
foreach ($parameters as $key => $value) {
if (!in_array($key, ['created', 'expires', 'nonce', 'alg', 'keyid', 'tag'])) {
return false;
}
}
}
if (isset($parameters['expires'])) {
$expires = (int) $parameters['expires'];
if ($expires < time()) {
@@ -308,12 +314,17 @@ class HttpMessageSigner
$fieldName = $field->value();
$parameters = $this->extractParameters($field);
if (isset($parameters['bs']) && isset($parameters['sf'])) {
throw new \Exception('Cannot use both bs and sf');
throw new UnProcessableSignatureException('Cannot use both bs and sf');
}
$whichRequest = $interface;
if (isset($parameters['req']) && $interface instanceof ResponseInterface) {
$whichRequest = $this->getOriginalRequest();
if (isset($parameters['req'])) {
if ($interface instanceof ResponseInterface) {
$whichRequest = $this->getOriginalRequest();
}
else {
throw new UnProcessableSignatureException('missing request for req parameter');
}
}
$whichHeaders = $headers;
@@ -412,7 +423,7 @@ class HttpMessageSigner
return ['"_' . $fieldName . '_"', $queryParams[$fieldName] ? '"' . $queryParams[$fieldName] . '"' : ''];
}
}
throw new \Exception('Query string named parameter not set');
throw new UnProcessableSignatureException('Query string named parameter not set');
}
private function applyStructuredField(string $name, string $fieldValue): string
@@ -423,11 +434,11 @@ class HttpMessageSigner
$field = OuterList::fromHttpValue($fieldValue);
break;
case 'innerlist':
$field = InnerList::fromHttpValue($fieldValue);
break;
$field = InnerList::fromHttpValue($fieldValue);
break;
case 'parameters':
$field = Parameters::fromHttpValue($fieldValue);
break;
$field = Parameters::fromHttpValue($fieldValue);
break;
case 'dictionary':
$field = Dictionary::fromHttpValue($fieldValue);
break;
@@ -455,7 +466,7 @@ class HttpMessageSigner
break;
}
if (!$field) {
return '';
throw new UnProcessableSignatureException('Unknown or unregistered structured field type');
}
return $field->toHttpValue();
}
@@ -472,23 +483,13 @@ class HttpMessageSigner
return '';
}
private function applyByteSequence(string $fieldValue): string
{
return $fieldValue;
}
private function applyTrailer(string $fieldValue): string
{
return $fieldValue;
}
private function createSignature(string $data): string
{
return match ($this->algorithm) {
'rsa-sha256' => $this->rsaSign($data),
'ed25519' => $this->ed25519Sign($data),
'hmac-sha256' => base64_encode(hash_hmac('sha256', $data, $this->privateKey, true)),
default => throw new \RuntimeException("Unsupported algorithm: $this->algorithm")
default => throw new UnProcessableSignatureException("Unsupported algorithm: $this->algorithm")
};
}
@@ -511,7 +512,7 @@ class HttpMessageSigner
private function rsaSign(string $data): string
{
if (!openssl_sign($data, $signature, $this->privateKey, OPENSSL_ALGO_SHA256)) {
throw new \RuntimeException("RSA signing failed");
throw new UnProcessableSignatureException("RSA signing failed");
}
return base64_encode($signature);
}
@@ -519,7 +520,7 @@ class HttpMessageSigner
private function ed25519Sign(string $data): string
{
if (!openssl_sign($data, $signature, $this->privateKey, "Ed25519")) {
throw new \RuntimeException("Ed25519 signing failed");
throw new UnProcessableSignatureException("Ed25519 signing failed");
}
return base64_encode($signature);
}
@@ -567,7 +568,7 @@ class HttpMessageSigner
}
}
if (!isset($algorithmHeaderString)) {
throw new \RuntimeException("Unsupported algorithm: $algorithm");
throw new UnProcessableSignatureException("Unsupported digest algorithm: $algorithm");
}
$digest = hash($algorithm, $body, true);
/**