Merge pull request #14700 from annando/get-signer

Issue 14692: Prevent loops with remote servers
This commit is contained in:
Hypolite Petovan 2025-01-22 20:50:41 -05:00 committed by GitHub
commit 3d1ab8c5b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -57,11 +57,13 @@ class HTTPSignature
// Decide if $data arrived via controller submission or curl. // Decide if $data arrived via controller submission or curl.
$headers = []; $headers = [];
$headers['(request-target)'] = strtolower(DI::args()->getMethod()) . ' ' . $_SERVER['REQUEST_URI']; $headers['(request-target)'] = strtolower(DI::args()->getMethod()) . ' ' . $_SERVER['REQUEST_URI'];
foreach ($_SERVER as $k => $v) { foreach ($_SERVER as $k => $v) {
if (strpos($k, 'HTTP_') === 0) { if (strpos($k, 'HTTP_') === 0) {
$field = str_replace('_', '-', strtolower(substr($k, 5))); $field = str_replace('_', '-', strtolower(substr($k, 5)));
$headers[$field] = $v; $headers[$field] = $v;
} }
} }
@ -98,6 +100,7 @@ class HTTPSignature
if ($key && function_exists($key)) { if ($key && function_exists($key)) {
$result['signer'] = $sig_block['keyId']; $result['signer'] = $sig_block['keyId'];
$key = $key($sig_block['keyId']); $key = $key($sig_block['keyId']);
} }
@ -387,7 +390,7 @@ class HTTPSignature
* @param int $gsid Server ID * @param int $gsid Server ID
* @throws \Exception * @throws \Exception
*/ */
static public function setInboxStatus(string $url, bool $success, bool $shared = false, int $gsid = null) public static function setInboxStatus(string $url, bool $success, bool $shared = false, int $gsid = null)
{ {
$now = DateTimeFormat::utcNow(); $now = DateTimeFormat::utcNow();
@ -604,13 +607,14 @@ class HTTPSignature
/** /**
* Gets a signer from a given HTTP request * Gets a signer from a given HTTP request
* *
* @param string $content * @param string $content Body of the request
* @param array $http_headers * @param array $http_headers array containing the HTTP headers
* @param ?boolean $update true = always update, false = never update, null = update when not found or outdated
* *
* @return string|null|false Signer * @return string|null|false Signer
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function getSigner(string $content, array $http_headers) public static function getSigner(string $content, array $http_headers, ?bool $update = null)
{ {
if (empty($http_headers['HTTP_SIGNATURE'])) { if (empty($http_headers['HTTP_SIGNATURE'])) {
DI::logger()->debug('No HTTP_SIGNATURE header'); DI::logger()->debug('No HTTP_SIGNATURE header');
@ -630,11 +634,13 @@ class HTTPSignature
} }
$headers = []; $headers = [];
$headers['(request-target)'] = strtolower(DI::args()->getMethod()) . ' ' . parse_url($http_headers['REQUEST_URI'], PHP_URL_PATH); $headers['(request-target)'] = strtolower(DI::args()->getMethod()) . ' ' . parse_url($http_headers['REQUEST_URI'], PHP_URL_PATH);
// First take every header // First take every header
foreach ($http_headers as $k => $v) { foreach ($http_headers as $k => $v) {
$field = str_replace('_', '-', strtolower($k)); $field = str_replace('_', '-', strtolower($k));
$headers[$field] = $v; $headers[$field] = $v;
} }
@ -642,6 +648,7 @@ class HTTPSignature
foreach ($http_headers as $k => $v) { foreach ($http_headers as $k => $v) {
if (strpos($k, 'HTTP_') === 0) { if (strpos($k, 'HTTP_') === 0) {
$field = str_replace('_', '-', strtolower(substr($k, 5))); $field = str_replace('_', '-', strtolower(substr($k, 5)));
$headers[$field] = $v; $headers[$field] = $v;
} }
} }
@ -700,7 +707,7 @@ class HTTPSignature
return false; return false;
} }
$key = self::fetchKey($sig_block['keyId'], $actor); $key = self::fetchKey($sig_block['keyId'], $actor, $update);
if (empty($key)) { if (empty($key)) {
DI::logger()->info('Empty key'); DI::logger()->info('Empty key');
return false; return false;
@ -802,17 +809,18 @@ class HTTPSignature
/** /**
* fetches a key for a given id and actor * fetches a key for a given id and actor
* *
* @param string $id * @param string $id keyId of the signature block
* @param string $actor * @param string $actor Actor URI
* @param ?boolean $update true = always update, false = never update, null = update when not found or outdated
* *
* @return array with actor url and public key * @return array with actor url and public key
* @throws \Exception * @throws \Exception
*/ */
private static function fetchKey(string $id, string $actor): array private static function fetchKey(string $id, string $actor, ?bool $update = null): array
{ {
$url = (strpos($id, '#') ? substr($id, 0, strpos($id, '#')) : $id); $url = (strpos($id, '#') ? substr($id, 0, strpos($id, '#')) : $id);
$profile = APContact::getByURL($url); $profile = APContact::getByURL($url, $update);
if (!empty($profile)) { if (!empty($profile)) {
DI::logger()->info('Taking key from id', ['id' => $id]); DI::logger()->info('Taking key from id', ['id' => $id]);
return ['url' => $url, 'pubkey' => $profile['pubkey'], 'type' => $profile['type']]; return ['url' => $url, 'pubkey' => $profile['pubkey'], 'type' => $profile['type']];