Browse Source

use signed gets for all parts of activitypub fetching including author profile info and likes/reposts

main
Aaron Parecki 1 month ago
parent
commit
2f2f4c135f
4 changed files with 50 additions and 9 deletions
  1. +5
    -2
      lib/XRay.php
  2. +15
    -3
      lib/XRay/Fetcher.php
  3. +21
    -3
      lib/XRay/Formats/ActivityStreams.php
  4. +9
    -1
      lib/XRay/Parser.php

+ 5
- 2
lib/XRay.php View File

@ -30,11 +30,14 @@ class XRay {
public function parse($url, $opts_or_body=false, $opts_for_body=[]) {
if(!$opts_or_body || is_array($opts_or_body)) {
$fetch = new XRay\Fetcher($this->http);
if (is_array($opts_or_body)) {
if(is_array($opts_or_body)) {
$fetch_opts = array_merge($this->defaultOptions, $opts_or_body);
} else {
$fetch_opts = $this->defaultOptions;
}
if(is_array($fetch_opts) && isset($fetch_opts['httpsig'])) {
$fetch->httpsig($fetch_opts['httpsig']);
}
$response = $fetch->fetch($url, $fetch_opts);
if(!empty($response['error']))
return $response;
@ -47,7 +50,7 @@ class XRay {
$opts = $opts_for_body;
$code = null;
}
$parser = new XRay\Parser($this->http);
$parser = new XRay\Parser($this->http, $fetch);
// Merge provided options with default options, allowing provided options to override defaults.
$opts = array_merge($this->defaultOptions, $opts);

+ 15
- 3
lib/XRay/Fetcher.php View File

@ -6,12 +6,17 @@ use DateTime;
class Fetcher {
private $http;
private $httpsig;
use HTTPSig;
public function __construct($http) {
$this->http = $http;
}
public function httpsig($key) {
$this->httpsig = $key;
}
public function fetch($url, $opts=[]) {
if($opts == false) $opts = [];
@ -66,7 +71,7 @@ class Fetcher {
$headers = [];
if(isset($opts['httpsig'])) {
if($this->httpsig) {
// If we're making a signed GET, include the default headers that mastodon requires as part of the signature
$date = new DateTime('UTC');
$date = $date->format('D, d M Y H:i:s \G\M\T');
@ -92,8 +97,7 @@ class Fetcher {
$headers['Authorization'] = 'Bearer ' . $opts['token'];
if(isset($opts['httpsig'])) {
echo "Signing HTTP Request\n";
$this->_httpSign($headers, $opts['httpsig']);
$this->_httpSign($headers, $this->httpsig);
}
$result = $this->http->get($url, $this->_headersToCurlArray($headers));
@ -176,6 +180,14 @@ class Fetcher {
'code' => $result['code'],
];
}
public function signed_get($url, $headers) {
$date = new DateTime('UTC');
$date = $date->format('D, d M Y H:i:s \G\M\T');
$headers = array_merge($headers, $this->_headersToSign($url, $date));
$this->_httpSign($headers, $this->httpsig);
return $this->http->get($url, $this->_headersToCurlArray($headers));
}
private function _fetch_github($url, $opts) {
$fields = ['github_access_token'];

+ 21
- 3
lib/XRay/Formats/ActivityStreams.php View File

@ -5,6 +5,8 @@ use DateTime;
use \p3k\XRay\PostType;
class ActivityStreams extends Format {
private static $fetcher;
public static function is_as2_json($document) {
if(is_array($document) && isset($document['@context'])) {
@ -28,6 +30,8 @@ class ActivityStreams extends Format {
public static function parse($http_response, $http, $opts=[]) {
$as2 = $http_response['body'];
$url = $http_response['url'];
self::$fetcher = $opts['fetcher'] ?? null;
if(!isset($as2['type']))
return false;
@ -156,7 +160,11 @@ class ActivityStreams extends Format {
$authorURL = $as2['actor'];
}
if($authorURL) {
$authorResponse = $http->get($authorURL, ['Accept: application/activity+json,application/json']);
if(self::$fetcher)
$authorResponse = self::$fetcher->signed_get($authorURL, ['Accept' => 'application/activity+json,application/json']);
else
$authorResponse = $http->get($authorURL, ['Accept: application/activity+json,application/json']);
if($authorResponse && !empty($authorResponse['body'])) {
$authorProfile = json_decode($authorResponse['body'], true);
$author = self::parseAsHCard($authorProfile, $authorURL, $http, $opts);
@ -168,7 +176,12 @@ class ActivityStreams extends Format {
// If this is a repost, fetch the reposted content
if($as2['type'] == 'Announce' && isset($as2['object']) && is_string($as2['object'])) {
$data['repost-of'] = [$as2['object']];
$reposted = $http->get($as2['object'], ['Accept: application/activity+json,application/json']);
if(self::$fetcher)
$reposted = self::$fetcher->signed_get($as2['object'], ['Accept: application/activity+json,application/json']);
else
$reposted = $http->get($as2['object'], ['Accept: application/activity+json,application/json']);
if($reposted && !empty($reposted['body'])) {
$repostedData = json_decode($reposted['body'], true);
if($repostedData) {
@ -184,7 +197,12 @@ class ActivityStreams extends Format {
// If this is a like, fetch the liked post
if($as2['type'] == 'Like' && isset($as2['object']) && is_string($as2['object'])) {
$data['like-of'] = [$as2['object']];
$liked = $http->get($as2['object'], ['Accept: application/activity+json,application/json']);
if(self::$fetcher)
$liked = self::$fetcher->signed_get($as2['object'], ['Accept: application/activity+json,application/json']);
else
$liked = $http->get($as2['object'], ['Accept: application/activity+json,application/json']);
if($liked && !empty($liked['body'])) {
$likedData = json_decode($liked['body'], true);
if($likedData) {

+ 9
- 1
lib/XRay/Parser.php View File

@ -6,9 +6,11 @@ use DOMDocument, DOMXPath;
class Parser {
private $http;
private $fetcher;
public function __construct($http) {
public function __construct($http, $fetcher=false) {
$this->http = $http;
$this->fetcher = $fetcher;
}
public function parse($http_response, $opts=[]) {
@ -109,6 +111,9 @@ class Parser {
// Check if an ActivityStreams JSON object was passed in
if(Formats\ActivityStreams::is_as2_json($body)) {
if($this->fetcher) {
$opts['fetcher'] = $this->fetcher;
}
$data = Formats\ActivityStreams::parse($http_response, $this->http, $opts);
$data['source-format'] = 'activity+json';
return $data;
@ -138,6 +143,9 @@ class Parser {
$data['source-format'] = 'mf2+json';
return $data;
} elseif($parsed && Formats\ActivityStreams::is_as2_json($parsed)) {
if($this->fetcher) {
$opts['fetcher'] = $this->fetcher;
}
// Check if an ActivityStreams JSON string was passed in
$http_response['body'] = $parsed;
$data = Formats\ActivityStreams::parse($http_response, $this->http, $opts);

Loading…
Cancel
Save