diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 606626192..8c8a25b6d 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -160,6 +160,7 @@ class Contact $fields['created'] = DateTimeFormat::utcNow(); } + $fields = DI::dbaDefinition()->truncateFieldsForTable('contact', $fields); DBA::insert('contact', $fields, $duplicate_mode); $contact = DBA::selectFirst('contact', [], ['id' => DBA::lastInsertId()]); if (!DBA::isResult($contact)) { @@ -191,6 +192,7 @@ class Contact */ public static function update(array $fields, array $condition, $old_fields = []) { + $fields = DI::dbaDefinition()->truncateFieldsForTable('contact', $fields); $ret = DBA::update('contact', $fields, $condition, $old_fields); // Apply changes to the "user-contact" table on dedicated fields diff --git a/src/Model/GServer.php b/src/Model/GServer.php index d0993141a..08cefba56 100644 --- a/src/Model/GServer.php +++ b/src/Model/GServer.php @@ -1330,7 +1330,7 @@ class GServer return false; } - $xrd = XML::parseString($curlResult->getBody()); + $xrd = XML::parseString($curlResult->getBody(), true); if (!is_object($xrd)) { return false; } diff --git a/src/Model/Item.php b/src/Model/Item.php index c00bd06de..741594f22 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -1649,13 +1649,13 @@ class Item $post = Post::selectFirst(['id'], ['uri-id' => $item['uri-id'], 'uid' => $uid]); if (!empty($post['id'])) { if (!empty($item['event-id'])) { - $post = Post::selectFirst(['event-id'], ['uri-id' => $item['uri-id'], 'uid' => $uid]); - if (!empty($post['event-id'])) { + $event_post = Post::selectFirst(['event-id'], ['uri-id' => $item['uri-id'], 'uid' => $uid]); + if (!empty($event_post['event-id'])) { $event = DBA::selectFirst('event', ['edited', 'start', 'finish', 'summary', 'desc', 'location', 'nofinish', 'adjust'], ['id' => $item['event-id']]); if (!empty($event)) { // We aren't using "Event::store" here, since we don't want to trigger any further action - $ret = DBA::update('event', $event, ['id' => $post['event-id']]); - Logger::info('Event updated', ['uid' => $uid, 'source-event' => $item['event-id'], 'target-event' => $post['event-id'], 'ret' => $ret]); + $ret = DBA::update('event', $event, ['id' => $event_post['event-id']]); + Logger::info('Event updated', ['uid' => $uid, 'source-event' => $item['event-id'], 'target-event' => $event_post['event-id'], 'ret' => $ret]); } } } diff --git a/src/Module/Api/Mastodon/PushSubscription.php b/src/Module/Api/Mastodon/PushSubscription.php index dc07ab55a..945ca6392 100644 --- a/src/Module/Api/Mastodon/PushSubscription.php +++ b/src/Module/Api/Mastodon/PushSubscription.php @@ -50,13 +50,13 @@ class PushSubscription extends BaseApi 'endpoint' => $request['subscription']['endpoint'] ?? '', 'pubkey' => $request['subscription']['keys']['p256dh'] ?? '', 'secret' => $request['subscription']['keys']['auth'] ?? '', - Notification::TYPE_FOLLOW => $request['data']['alerts'][Notification::TYPE_FOLLOW] ?? false, - Notification::TYPE_LIKE => $request['data']['alerts'][Notification::TYPE_LIKE] ?? false, - Notification::TYPE_RESHARE => $request['data']['alerts'][Notification::TYPE_RESHARE] ?? false, - Notification::TYPE_MENTION => $request['data']['alerts'][Notification::TYPE_MENTION] ?? false, - Notification::TYPE_POLL => $request['data']['alerts'][Notification::TYPE_POLL] ?? false, - Notification::TYPE_INTRODUCTION => $request['data']['alerts'][Notification::TYPE_INTRODUCTION] ?? false, - Notification::TYPE_POST => $request['data']['alerts'][Notification::TYPE_POST] ?? false, + Notification::TYPE_FOLLOW => filter_var($request['data']['alerts'][Notification::TYPE_FOLLOW] ?? false, FILTER_VALIDATE_BOOLEAN), + Notification::TYPE_LIKE => filter_var($request['data']['alerts'][Notification::TYPE_LIKE] ?? false, FILTER_VALIDATE_BOOLEAN), + Notification::TYPE_RESHARE => filter_var($request['data']['alerts'][Notification::TYPE_RESHARE] ?? false, FILTER_VALIDATE_BOOLEAN), + Notification::TYPE_MENTION => filter_var($request['data']['alerts'][Notification::TYPE_MENTION] ?? false, FILTER_VALIDATE_BOOLEAN), + Notification::TYPE_POLL => filter_var($request['data']['alerts'][Notification::TYPE_POLL] ?? false, FILTER_VALIDATE_BOOLEAN), + Notification::TYPE_INTRODUCTION => filter_var($request['data']['alerts'][Notification::TYPE_INTRODUCTION] ?? false, FILTER_VALIDATE_BOOLEAN), + Notification::TYPE_POST => filter_var($request['data']['alerts'][Notification::TYPE_POST] ?? false, FILTER_VALIDATE_BOOLEAN), ]; $ret = Subscription::replace($subscription); diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 8c68bcba6..10ff58b4b 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -113,9 +113,16 @@ class Receiver APContact::unmarkForArchival($apcontact); } + $sig_contact = HTTPSignature::getKeyIdContact($header); + if (APContact::isRelay($sig_contact)) { + Logger::info('Message from a relay', ['url' => $sig_contact['url']]); + self::processRelayPost($ldactivity, $sig_contact['url']); + return; + } + $http_signer = HTTPSignature::getSigner($body, $header); if ($http_signer === false) { - Logger::warning('Invalid HTTP signature, message will be discarded.'); + Logger::warning('Invalid HTTP signature, message will be discarded.', ['uid' => $uid, 'actor' => $actor, 'header' => $header, 'body' => $body]); return; } elseif (empty($http_signer)) { Logger::info('Signer is a tombstone. The message will be discarded, the signer account is deleted.'); @@ -170,18 +177,43 @@ class Receiver { $type = JsonLD::fetchElement($activity, '@type'); if (!$type) { - Logger::info('Empty type', ['activity' => $activity, 'actor' => $actor]); + Logger::notice('Empty type', ['activity' => $activity, 'actor' => $actor]); return; } - if ($type != 'as:Announce') { - Logger::info('Not an announcement', ['activity' => $activity, 'actor' => $actor]); - return; - } + $object_type = JsonLD::fetchElement($activity, 'as:object', '@type') ?? ''; $object_id = JsonLD::fetchElement($activity, 'as:object', '@id'); if (empty($object_id)) { - Logger::info('No object id found', ['activity' => $activity, 'actor' => $actor]); + Logger::notice('No object id found', ['type' => $type, 'object_type' => $object_type, 'actor' => $actor, 'activity' => $activity]); + return; + } + + $handle = ($type == 'as:Announce'); + + if (!$handle && in_array($type, ['as:Create', 'as:Update'])) { + $handle = in_array($object_type, self::CONTENT_TYPES); + } + + if (!$handle) { + $trust_source = false; + $object_data = self::prepareObjectData($activity, 0, false, $trust_source); + + if (!$trust_source) { + Logger::notice('Activity trust could not be achieved.', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor, 'activity' => $activity]); + return; + } + + if (empty($object_data)) { + Logger::notice('No object data found', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor, 'activity' => $activity]); + return; + } + + if (self::routeActivities($object_data, $type, true)) { + Logger::debug('Handled activity', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor]); + } else { + Logger::info('Unhandled activity', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor, 'activity' => $activity]); + } return; } @@ -196,7 +228,7 @@ class Receiver return; } - Logger::info('Got relayed message id', ['id' => $object_id, 'actor' => $actor]); + Logger::debug('Got relayed message id', ['id' => $object_id, 'actor' => $actor]); $item_id = Item::searchByLink($object_id); if ($item_id) { diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index 6531d75af..3758b0fe6 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -1169,10 +1169,6 @@ class OStatus ]; XML::addElement($doc, $root, 'link', '', $attributes); break; - - default: - Logger::warning('Unsupported type', ['type' => $siteinfo['type'], 'url' => $siteinfo['url'] ?? '']); - break; } if (!DI::config()->get('system', 'ostatus_not_attach_preview') && ($siteinfo['type'] != 'photo') && isset($siteinfo['image'])) { diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index f4f0a4e85..225a2bcf2 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -485,6 +485,31 @@ class HTTPSignature return $curlResult; } + /** + * Fetch the apcontact entry of the keyId in the given header + * + * @param array $http_headers + * + * @return array APContact entry + */ + public static function getKeyIdContact(array $http_headers): array + { + if (empty($http_headers['HTTP_SIGNATURE'])) { + Logger::debug('No HTTP_SIGNATURE header', ['header' => $http_headers]); + return []; + } + + $sig_block = self::parseSigHeader($http_headers['HTTP_SIGNATURE']); + + if (empty($sig_block['keyId'])) { + Logger::debug('No keyId', ['sig_block' => $sig_block]); + return []; + } + + $url = (strpos($sig_block['keyId'], '#') ? substr($sig_block['keyId'], 0, strpos($sig_block['keyId'], '#')) : $sig_block['keyId']); + return APContact::getByURL($url); + } + /** * Gets a signer from a given HTTP request * diff --git a/src/Worker/UpdateContacts.php b/src/Worker/UpdateContacts.php index e6469fe19..31426e79f 100644 --- a/src/Worker/UpdateContacts.php +++ b/src/Worker/UpdateContacts.php @@ -55,7 +55,7 @@ class UpdateContacts $condition = array_merge(['local-data' => true], $condition); } - $condition = array_merge(["`next-update` < ?", DateTimeFormat::utcNow()], $condition); + $condition = DBA::mergeConditions(["`next-update` < ?", DateTimeFormat::utcNow()], $condition); $contacts = DBA::select('contact', ['id'], $condition, ['order' => ['next-update'], 'limit' => $limit]); $count = 0; while ($contact = DBA::fetch($contacts)) {