diff --git a/mod/display.php b/mod/display.php index 21e28d5617..047f752c98 100644 --- a/mod/display.php +++ b/mod/display.php @@ -77,7 +77,7 @@ function display_init(App $a) displayShowFeed($item["id"], false); } - if (stristr(defaults($_SERVER, 'HTTP_ACCEPT', ''), 'application/activity+json')) { + if (ActivityPub::isRequest()) { $wall_item = Item::selectFirst(['id', 'uid'], ['guid' => $item['guid'], 'wall' => true]); if ($wall_item['uid'] == 180) { $data = ActivityPub::createActivityFromItem($wall_item['id']); diff --git a/mod/profile.php b/mod/profile.php index fd23964e41..a284e10f2d 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -50,7 +50,7 @@ function profile_init(App $a) DFRN::autoRedir($a, $which); } - if (stristr(defaults($_SERVER, 'HTTP_ACCEPT', ''), 'application/activity+json')) { + if (ActivityPub::isRequest()) { $user = DBA::selectFirst('user', ['uid'], ['nickname' => $which]); if ($user['uid'] == 180) { $data = ActivityPub::profile($user['uid']); diff --git a/src/Module/Inbox.php b/src/Module/Inbox.php index d47419a415..21dd77151c 100644 --- a/src/Module/Inbox.php +++ b/src/Module/Inbox.php @@ -47,6 +47,6 @@ class Inbox extends BaseModule ActivityPub::processInbox($postdata, $_SERVER, $uid); - System::httpExit(202); + System::httpExit(201); } } diff --git a/src/Protocol/ActivityPub.php b/src/Protocol/ActivityPub.php index ad27535ae6..5b5d16e85a 100644 --- a/src/Protocol/ActivityPub.php +++ b/src/Protocol/ActivityPub.php @@ -55,6 +55,12 @@ class ActivityPub { const PUBLIC = 'https://www.w3.org/ns/activitystreams#Public'; + public static function isRequest() + { + return stristr(defaults($_SERVER, 'HTTP_ACCEPT', ''), 'application/activity+json') || + stristr(defaults($_SERVER, 'HTTP_ACCEPT', ''), 'application/ld+json'); + } + public static function transmit($data, $target, $uid) { $owner = User::getOwnerDataById($uid); @@ -66,19 +72,19 @@ class ActivityPub $content = json_encode($data); // Header data that is about to be signed. - /// @todo Add "digest" $host = parse_url($target, PHP_URL_HOST); $path = parse_url($target, PHP_URL_PATH); - $date = date('r'); + $digest = 'SHA-256=' . base64_encode(hash('sha256', $content, true)); $content_length = strlen($content); - $headers = ['Host: ' . $host, 'Date: ' . $date, 'Content-Length: ' . $content_length]; + $headers = ['Content-Length: ' . $content_length, 'Digest: ' . $digest, 'Host: ' . $host]; - $signed_data = "(request-target): post " . $path . "\nhost: " . $host . "\ndate: " . $date . "\ncontent-length: " . $content_length; + $signed_data = "(request-target): post " . $path . "\ncontent-length: " . $content_length . "\ndigest: " . $digest . "\nhost: " . $host; $signature = base64_encode(Crypto::rsaSign($signed_data, $owner['uprvkey'], 'sha256')); - $headers[] = 'Signature: keyId="' . $owner['url'] . '#main-key' . '",headers="(request-target) host date content-length",signature="' . $signature . '"'; + $headers[] = 'Signature: keyId="' . $owner['url'] . '#main-key' . '",algorithm="rsa-sha256",headers="(request-target) content-length digest host",signature="' . $signature . '"'; + $headers[] = 'Content-Type: application/activity+json'; Network::post($target, $content, $headers); @@ -157,7 +163,7 @@ class ActivityPub 'toot' => 'http://joinmastodon.org/ns#']]]; $data['type'] = 'Create'; - $data['id'] = $item['uri']; + $data['id'] = $item['uri'] . '/activity'; $data['actor'] = $item['author-link']; $data['to'] = 'https://www.w3.org/ns/activitystreams#Public'; $data['object'] = self::createNote($item); @@ -210,7 +216,8 @@ class ActivityPub 'id' => System::baseUrl() . '/activity/' . System::createGUID(), 'type' => $activity, 'actor' => $owner['url'], - 'object' => $profile['url']]; + 'object' => $profile['url'], + 'to' => $profile['url']]; logger('Sending activity ' . $activity . ' to ' . $target . ' for user ' . $uid, LOGGER_DEBUG); return self::transmit($data, $profile['notify'], $uid); @@ -227,7 +234,8 @@ class ActivityPub 'actor' => $owner['url'], 'object' => ['id' => $id, 'type' => 'Follow', 'actor' => $profile['url'], - 'object' => $owner['url']]]; + 'object' => $owner['url']], + 'to' => $profile['url']]; logger('Sending accept to ' . $target . ' for user ' . $uid . ' with id ' . $id, LOGGER_DEBUG); return self::transmit($data, $profile['notify'], $uid); @@ -244,7 +252,8 @@ class ActivityPub 'actor' => $owner['url'], 'object' => ['id' => $id, 'type' => 'Follow', 'actor' => $profile['url'], - 'object' => $owner['url']]]; + 'object' => $owner['url']], + 'to' => $profile['url']]; logger('Sending reject to ' . $target . ' for user ' . $uid . ' with id ' . $id, LOGGER_DEBUG); return self::transmit($data, $profile['notify'], $uid); @@ -263,7 +272,8 @@ class ActivityPub 'actor' => $owner['url'], 'object' => ['id' => $id, 'type' => 'Follow', 'actor' => $owner['url'], - 'object' => $profile['url']]]; + 'object' => $profile['url']], + 'to' => $profile['url']]; logger('Sending undo to ' . $target . ' for user ' . $uid . ' with id ' . $id, LOGGER_DEBUG); return self::transmit($data, $profile['notify'], $uid); @@ -277,7 +287,7 @@ class ActivityPub */ public static function fetchContent($url) { - $ret = Network::curl($url, false, $redirects, ['accept_content' => 'application/activity+json']); + $ret = Network::curl($url, false, $redirects, ['accept_content' => 'application/activity+json, application/ld+json']); if (!$ret['success'] || empty($ret['body'])) { return; } diff --git a/src/Worker/Delivery.php b/src/Worker/Delivery.php index ef3a34649d..8ee00af630 100644 --- a/src/Worker/Delivery.php +++ b/src/Worker/Delivery.php @@ -440,24 +440,21 @@ q * // send comments and likes to owner to relay logger('ActivityPub followup: ' . $loc); $data = ActivityPub::createActivityFromItem($target_item['id']); - $content = json_encode($data); - ActivityPub::transmit($content, $contact['notify'], $owner['uid']); + ActivityPub::transmit($data, $contact['notify'], $owner['uid']); // ActivityPub::sendFollowup($target_item, $owner, $contact, $public_message); return; } elseif ($target_item['uri'] !== $target_item['parent-uri']) { // we are the relay - send comments, likes and relayable_retractions to our conversants logger('ActivityPub relay: ' . $loc); $data = ActivityPub::createActivityFromItem($target_item['id']); - $content = json_encode($data); - ActivityPub::transmit($content, $contact['notify'], $owner['uid']); + ActivityPub::transmit($data, $contact['notify'], $owner['uid']); // ActivityPub::sendRelay($target_item, $owner, $contact, $public_message); return; } elseif ($top_level && !$walltowall) { // currently no workable solution for sending walltowall logger('ActivityPub status: ' . $loc); $data = ActivityPub::createActivityFromItem($target_item['id']); - $content = json_encode($data); - ActivityPub::transmit($content, $contact['notify'], $owner['uid']); + ActivityPub::transmit($data, $contact['notify'], $owner['uid']); // ActivityPub::sendStatus($target_item, $owner, $contact, $public_message); return; }