mirror of
https://github.com/friendica/friendica
synced 2025-02-06 05:38:50 +00:00
Merge pull request #14700 from annando/get-signer
Issue 14692: Prevent loops with remote servers
This commit is contained in:
commit
3d1ab8c5b9
1 changed files with 38 additions and 30 deletions
|
@ -49,19 +49,21 @@ class HTTPSignature
|
|||
{
|
||||
$headers = null;
|
||||
$spoofable = false;
|
||||
$result = [
|
||||
'signer' => '',
|
||||
'header_signed' => false,
|
||||
'header_valid' => false
|
||||
$result = [
|
||||
'signer' => '',
|
||||
'header_signed' => false,
|
||||
'header_valid' => false
|
||||
];
|
||||
|
||||
// Decide if $data arrived via controller submission or curl.
|
||||
$headers = [];
|
||||
|
||||
$headers['(request-target)'] = strtolower(DI::args()->getMethod()) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
|
||||
foreach ($_SERVER as $k => $v) {
|
||||
if (strpos($k, 'HTTP_') === 0) {
|
||||
$field = str_replace('_', '-', strtolower(substr($k, 5)));
|
||||
|
||||
$headers[$field] = $v;
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +100,7 @@ class HTTPSignature
|
|||
|
||||
if ($key && function_exists($key)) {
|
||||
$result['signer'] = $sig_block['keyId'];
|
||||
|
||||
$key = $key($sig_block['keyId']);
|
||||
}
|
||||
|
||||
|
@ -136,7 +139,7 @@ class HTTPSignature
|
|||
$return_headers = $head;
|
||||
}
|
||||
|
||||
$alg = 'sha512';
|
||||
$alg = 'sha512';
|
||||
$algorithm = 'rsa-sha512';
|
||||
|
||||
$x = self::sign($head, $prvkey, $alg);
|
||||
|
@ -158,7 +161,7 @@ class HTTPSignature
|
|||
*/
|
||||
private static function sign(array $head, string $prvkey, string $alg = 'sha256'): array
|
||||
{
|
||||
$ret = [];
|
||||
$ret = [];
|
||||
$headers = '';
|
||||
$fields = '';
|
||||
|
||||
|
@ -220,10 +223,10 @@ class HTTPSignature
|
|||
}
|
||||
|
||||
$return = [
|
||||
'keyId' => $headers['keyId'] ?? '',
|
||||
'keyId' => $headers['keyId'] ?? '',
|
||||
'algorithm' => $headers['algorithm'] ?? 'rsa-sha256',
|
||||
'created' => $headers['created'] ?? null,
|
||||
'expires' => $headers['expires'] ?? null,
|
||||
'created' => $headers['created'] ?? null,
|
||||
'expires' => $headers['expires'] ?? null,
|
||||
'headers' => explode(' ', $headers['headers'] ?? ''),
|
||||
'signature' => base64_decode(preg_replace('/\s+/', '', $headers['signature'] ?? '')),
|
||||
];
|
||||
|
@ -268,17 +271,17 @@ class HTTPSignature
|
|||
$content = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// Header data that is about to be signed.
|
||||
$host = strtolower(parse_url($target, PHP_URL_HOST));
|
||||
$path = parse_url($target, PHP_URL_PATH);
|
||||
$digest = 'SHA-256=' . base64_encode(hash('sha256', $content, true));
|
||||
$host = strtolower(parse_url($target, PHP_URL_HOST));
|
||||
$path = parse_url($target, PHP_URL_PATH);
|
||||
$digest = 'SHA-256=' . base64_encode(hash('sha256', $content, true));
|
||||
$content_length = strlen($content);
|
||||
$date = DateTimeFormat::utcNow(DateTimeFormat::HTTP);
|
||||
$date = DateTimeFormat::utcNow(DateTimeFormat::HTTP);
|
||||
|
||||
$headers = [
|
||||
'Date' => $date,
|
||||
'Date' => $date,
|
||||
'Content-Length' => $content_length,
|
||||
'Digest' => $digest,
|
||||
'Host' => $host
|
||||
'Digest' => $digest,
|
||||
'Host' => $host
|
||||
];
|
||||
|
||||
$signed_data = "(request-target): post " . $path . "\ndate: " . $date . "\ncontent-length: " . $content_length . "\ndigest: " . $digest . "\nhost: " . $host;
|
||||
|
@ -289,7 +292,7 @@ class HTTPSignature
|
|||
|
||||
$headers['Content-Type'] = 'application/activity+json';
|
||||
|
||||
$postResult = DI::httpClient()->post($target, $content, $headers, DI::config()->get('system', 'curl_timeout'), HttpClientRequest::ACTIVITYPUB);
|
||||
$postResult = DI::httpClient()->post($target, $content, $headers, DI::config()->get('system', 'curl_timeout'), HttpClientRequest::ACTIVITYPUB);
|
||||
$return_code = $postResult->getReturnCode();
|
||||
|
||||
DI::logger()->info('Transmit to ' . $target . ' returned ' . $return_code);
|
||||
|
@ -318,10 +321,10 @@ class HTTPSignature
|
|||
return false;
|
||||
}
|
||||
|
||||
$activity = JsonLD::compact($data);
|
||||
$type = JsonLD::fetchElement($activity, '@type');
|
||||
$activity = JsonLD::compact($data);
|
||||
$type = JsonLD::fetchElement($activity, '@type');
|
||||
$trust_source = true;
|
||||
$object_data = Receiver::prepareObjectData($activity, $uid, true, $trust_source, $owner['url']);
|
||||
$object_data = Receiver::prepareObjectData($activity, $uid, true, $trust_source, $owner['url']);
|
||||
if (empty($object_data)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -387,7 +390,7 @@ class HTTPSignature
|
|||
* @param int $gsid Server ID
|
||||
* @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();
|
||||
|
||||
|
@ -434,7 +437,7 @@ class HTTPSignature
|
|||
$stamp1 = strtotime($status['success']);
|
||||
}
|
||||
|
||||
$stamp2 = strtotime($now);
|
||||
$stamp2 = strtotime($now);
|
||||
$previous_stamp = strtotime($status['previous']);
|
||||
|
||||
// Archive the inbox when there had been failures for five days.
|
||||
|
@ -604,13 +607,14 @@ class HTTPSignature
|
|||
/**
|
||||
* Gets a signer from a given HTTP request
|
||||
*
|
||||
* @param string $content
|
||||
* @param array $http_headers
|
||||
* @param string $content Body of the request
|
||||
* @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
|
||||
* @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'])) {
|
||||
DI::logger()->debug('No HTTP_SIGNATURE header');
|
||||
|
@ -630,11 +634,13 @@ class HTTPSignature
|
|||
}
|
||||
|
||||
$headers = [];
|
||||
|
||||
$headers['(request-target)'] = strtolower(DI::args()->getMethod()) . ' ' . parse_url($http_headers['REQUEST_URI'], PHP_URL_PATH);
|
||||
|
||||
// First take every header
|
||||
foreach ($http_headers as $k => $v) {
|
||||
$field = str_replace('_', '-', strtolower($k));
|
||||
|
||||
$headers[$field] = $v;
|
||||
}
|
||||
|
||||
|
@ -642,6 +648,7 @@ class HTTPSignature
|
|||
foreach ($http_headers as $k => $v) {
|
||||
if (strpos($k, 'HTTP_') === 0) {
|
||||
$field = str_replace('_', '-', strtolower(substr($k, 5)));
|
||||
|
||||
$headers[$field] = $v;
|
||||
}
|
||||
}
|
||||
|
@ -700,7 +707,7 @@ class HTTPSignature
|
|||
return false;
|
||||
}
|
||||
|
||||
$key = self::fetchKey($sig_block['keyId'], $actor);
|
||||
$key = self::fetchKey($sig_block['keyId'], $actor, $update);
|
||||
if (empty($key)) {
|
||||
DI::logger()->info('Empty key');
|
||||
return false;
|
||||
|
@ -802,17 +809,18 @@ class HTTPSignature
|
|||
/**
|
||||
* fetches a key for a given id and actor
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $actor
|
||||
* @param string $id keyId of the signature block
|
||||
* @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
|
||||
* @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);
|
||||
|
||||
$profile = APContact::getByURL($url);
|
||||
$profile = APContact::getByURL($url, $update);
|
||||
if (!empty($profile)) {
|
||||
DI::logger()->info('Taking key from id', ['id' => $id]);
|
||||
return ['url' => $url, 'pubkey' => $profile['pubkey'], 'type' => $profile['type']];
|
||||
|
|
Loading…
Add table
Reference in a new issue