From b3a26788eb4e02784d65b3cf729c5df4fd2ce241 Mon Sep 17 00:00:00 2001 From: Alex Kirk Date: Fri, 2 Dec 2022 13:43:09 +0100 Subject: [PATCH] Add test for announce --- .../class-friends-feed-parser-activitypub.php | 16 +- tests/bootstrap.php | 2 + ...z-blog-2022-11-14-the-at-protocol.response | 1 + ...-class-friends-feed-parser-activitypub.php | 201 ++++++++++++++---- 4 files changed, 169 insertions(+), 51 deletions(-) create mode 100644 tests/fixtures/notiz-blog-2022-11-14-the-at-protocol.response diff --git a/integration/class-friends-feed-parser-activitypub.php b/integration/class-friends-feed-parser-activitypub.php index 80eabc7..79ded63 100644 --- a/integration/class-friends-feed-parser-activitypub.php +++ b/integration/class-friends-feed-parser-activitypub.php @@ -156,9 +156,8 @@ class Friends_Feed_Parser_ActivityPub extends \Friends\Feed_Parser { ), true ) ) { - return false; + return false; } - $actor_url = $object['actor']; $user_feed = false; if ( \wp_http_validate_url( $actor_url ) ) { @@ -216,8 +215,13 @@ class Friends_Feed_Parser_ActivityPub extends \Friends\Feed_Parser { * @param \Friends\User_Feed $user_feed The user feed. */ private function handle_incoming_post( $object, \Friends\User_Feed $user_feed ) { + $permalink = $object['id']; + if ( isset( $object['url'] ) ) { + $permalink = $object['url']; + } + $data = array( - 'permalink' => $object['url'], + 'permalink' => $permalink, 'content' => $object['content'], 'post_format' => $this->map_type_to_post_format( $object['type'] ), 'date' => $object['published'], @@ -236,7 +240,7 @@ class Friends_Feed_Parser_ActivityPub extends \Friends\Feed_Parser { $this->log( 'Received feed item', array( - 'url' => $object['url'], + 'url' => $permalink, 'data' => $data, ) ); @@ -254,10 +258,12 @@ class Friends_Feed_Parser_ActivityPub extends \Friends\Feed_Parser { * @param \Friends\User_Feed $user_feed The user feed. */ private function handle_incoming_announce( $url, \Friends\User_Feed $user_feed, $user_id ) { - $this->log( 'Received announce for ' . $url ); if ( ! \wp_http_validate_url( $url ) ) { + $this->log( 'Received invalid announce', compact( 'url' ) ); return false; } + $this->log( 'Received announce for ' . $url ); + $response = \Activitypub\safe_remote_get( $url, $user_id ); if ( \is_wp_error( $response ) ) { return $response; diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 67da18a..3867ab2 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -19,6 +19,8 @@ require_once $_tests_dir . '/includes/functions.php'; */ function _manually_load_plugin() { require \dirname( \dirname( __FILE__ ) ) . '/activitypub.php'; + + // Load the Friends plugin if available to test the integrations. $friends_plugin = \dirname( \dirname( \dirname( __FILE__ ) ) ) . '/friends/friends.php'; if ( file_exists( $friends_plugin ) ) { require $friends_plugin; diff --git a/tests/fixtures/notiz-blog-2022-11-14-the-at-protocol.response b/tests/fixtures/notiz-blog-2022-11-14-the-at-protocol.response new file mode 100644 index 0000000..d6705a1 --- /dev/null +++ b/tests/fixtures/notiz-blog-2022-11-14-the-at-protocol.response @@ -0,0 +1 @@ +a:3:{s:7:"headers";a:15:{s:4:"date";s:29:"Fri, 02 Dec 2022 12:09:11 GMT";s:12:"content-type";s:25:"application/activity+json";s:6:"server";s:5:"nginx";s:15:"x-xrds-location";s:24:"https://notiz.blog/?xrds";s:16:"x-yadis-location";s:24:"https://notiz.blog/?xrds";s:10:"x-pingback";s:29:"https://notiz.blog/xmlrpc.php";s:4:"link";s:541:"; rel="micropub_media", ; rel="micropub", ; rel="friends-base-url", ; rel="webmention", ; rel="http://webmention.org/", ; rel="https://api.w.org/", ; rel="alternate"; type="application/json", ; rel=shortlink";s:13:"cache-control";s:17:"max-age=0, public";s:7:"expires";s:29:"Fri, 02 Dec 2022 12:09:11 GMT";s:16:"x-xss-protection";s:13:"1; mode=block";s:22:"x-content-type-options";s:7:"nosniff";s:25:"strict-transport-security";s:16:"max-age=31536000";s:15:"x-frame-options";s:10:"SAMEORIGIN";s:15:"referrer-policy";s:31:"strict-origin-when-cross-origin";s:17:"x-clacks-overhead";s:19:"GNU Terry Pratchett";}s:4:"body";s:18048:"{"@context":["https:\/\/www.w3.org\/ns\/activitystreams","https:\/\/w3id.org\/security\/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","PropertyValue":"schema:PropertyValue","schema":"http:\/\/schema.org#","pt":"https:\/\/joinpeertube.org\/ns#","toot":"http:\/\/joinmastodon.org\/ns#","value":"schema:value","Hashtag":"as:Hashtag","featured":{"@id":"toot:featured","@type":"@id"},"featuredTags":{"@id":"toot:featuredTags","@type":"@id"}}],"id":"https:\/\/notiz.blog\/2022\/11\/14\/the-at-protocol\/","type":"Note","published":"2022-11-14T16:49:01Z","attributedTo":"https:\/\/notiz.blog\/author\/matthias-pfefferle\/","summary":null,"inReplyTo":null,"content":"\u003Cp\u003EVor zwei Jahren wollte Twitter in das \u201eDezentrale Netzwerke\u201c-Business einsteigen und gr\u00fcndete eigens daf\u00fcr das \u003Ca href=\u0022https:\/\/notiz.blog\/2019\/12\/13\/twitiverse\/\u0022 data-type=\u0022post\u0022 data-id=\u002218831\u0022\u003EProjekt Bluesky\u003C\/a\u003E. In den folgenden zwei Jahren wurde viel evaluiert und diskutiert, was wohl die beste L\u00f6sung f\u00fcr Twitter sei und wir alle \u003Cem\u003Efieberten\u003C\/em\u003E mit ob es nun \u003Ca href=\u0022https:\/\/www.w3.org\/TR\/activitypub\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/www.w3.org\/TR\/activitypub\/\u0022\u003EActivityPub\u003C\/a\u003E oder doch \u003Ca href=\u0022https:\/\/matrix.org\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/matrix.org\/\u0022\u003EMatrix\u003C\/a\u003E werden w\u00fcrde\u2026 \u003C\/p\u003E\u003Cp\u003EAber das Warten hat ein Ende! \u003Ca href=\u0022https:\/\/blueskyweb.xyz\/blog\/10-18-2022-the-at-protocol\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/blueskyweb.xyz\/blog\/10-18-2022-the-at-protocol\u0022\u003EBluesky hat verk\u00fcndet wie es weiter geht\u003C\/a\u003E!\u003C\/p\u003E\u003Cp\u003E\u003Cstrong\u003ESie entwickeln ein neues Protokoll!\u003C\/strong\u003E\u003C\/p\u003E\u003Cp\u003EDas \u003Cem\u003EAT Protocol\u003C\/em\u003E, kurz f\u00fcr \u003Cem\u003EAuthenticated Transfer Protocol\u003C\/em\u003E!\u003C\/p\u003E\u003Cp\u003EIch hab mir die \u003Ca href=\u0022https:\/\/atproto.com\/guides\/faq\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/atproto.com\/guides\/faq\u0022\u003EFAQ\u003C\/a\u003E mal angeschaut und dort steht warum Bluesky sich gegen ActivityPub entschieden hat:\u003C\/p\u003E\u003Cblockquote class=\u0022wp-block-quote\u0022\u003E\n\u003Cp\u003EAccount portability is the major reason why we chose to build a separate protocol. We consider portability to be crucial because it protects users from sudden bans, server shutdowns, and policy disagreements. Our solution for portability requires both \u003Ca href=\u0022https:\/\/atproto.com\/guides\/data-repos\u0022\u003Esigned data repositories\u003C\/a\u003E and \u003Ca href=\u0022https:\/\/atproto.com\/guides\/identity\u0022\u003EDIDs\u003C\/a\u003E, neither of which are easy to retrofit into ActivityPub. The migration tools for ActivityPub are comparatively limited; they require the original server to provide a redirect and cannot migrate the user\u2019s previous data.\u003C\/p\u003E\n\u003C\/blockquote\u003E\u003Cp\u003EDas erinnert mich ein bisschen an die Subline von meinem \u003Ca href=\u0022https:\/\/pfefferle.dev\/openwebicons\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/pfefferle.dev\/openwebicons\/\u0022\u003EOpenWeb-Icons Font\u003C\/a\u003E:\u003C\/p\u003E\u003Cblockquote class=\u0022wp-block-quote\u0022\u003E\n\u003Cp\u003EWhy \u003Cem\u003EOpenWeb Icons\u003C\/em\u003E? Because \u003Ca href=\u0022https:\/\/fortawesome.com\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/fortawesome.com\/\u0022\u003EFont Awesome\u003C\/a\u003E had no RSS-icon [\u2026]\u003C\/p\u003E\n\u003C\/blockquote\u003E\u003Cp\u003E\u003Cstrong\u003EWeil ActivityPub keine perfekte L\u00f6sung f\u00fcr \u201eAccount portability\u201c hat, bauen sie ein komplett neues Protokoll?\u003C\/strong\u003E\u003C\/p\u003E\u003Cp\u003EActivityPub ist sicherlich nicht \u201efeature complete\u201c, aber ein guter erster Wurf, was das Fediverse erfolgreich bewiesen hat! Warum arbeitet Twitter also lieber an einem eigen Format anstatt mit dem W3C zusammen an ActivityPub v2?\u003C\/p\u003E\u003Cp\u003EWarum macht sich das W3C \u00fcberhaupt noch die M\u00fche \u201eStandards\u201c zu definieren?\u003C\/p\u003E\u003Cp\u003E\u003Cstrong\u003EWegen der Interoperabilit\u00e4t!\u003C\/strong\u003E\u003C\/p\u003E\u003Cp\u003EW\u00fcrde Twitter mit HTTP(S), HTML oder CSS \u00e4hnlich umgehen, w\u00fcrde der Browser einfach leer bleiben, weil das \u0026$%\u00a7\u0026 Internet nur mit einheitlichen Standards funktioniert!\u003C\/p\u003E\u003Cp\u003EUnd das gleiche gilt auch f\u00fcr dezentralte Netze, zumindest wenn sie erfolgreich sein wollen! Dar\u00fcber hab ich tragischerweise schon vor \u003Cstrong\u003E10 Jahren\u003C\/strong\u003E geschrieben!\u003C\/p\u003E\u003Cblockquote class=\u0022wp-block-quote\u0022\u003E\n\u003Cp\u003EDiaspora* wurde kaum \u003Ca href=\u0022https:\/\/web.archive.org\/web\/20130630113539\/http:\/\/blog.diasporafoundation.org\/2012\/08\/27\/announcement-diaspora-will-now-be-a-community-project.html\u0022\u003Ef\u00fcr \u201etot\u201c erkl\u00e4rt\u003C\/a\u003E und schon steht das n\u00e4chste Projekt in den Startl\u00f6chern! \u003Ca href=\u0022https:\/\/web.archive.org\/web\/20190603031810\/https:\/\/tent.io\/\u0022\u003ETent.io\u003C\/a\u003E soll ein protocol for distributed social networking and personal data storage werden. Alles neu, alles anders, alles besser als OStatus, DiSo oder Diaspora*. Aber mal ganz ehrlich\u2026 was haben die Diasporas \u0026 Co. bisher geschaffen? Ziel war es Facebooks \u201eWalled Gardens\u201c aufzubrechen und was kam wirklich dabei rum? Eine ganze Reihe an dezentralen \u201eWalled Gardens\u201c. Na danke!\u003C\/p\u003E\n\u003Ccite\u003E\u003Ca href=\u0022https:\/\/notiz.blog\/2012\/11\/15\/dezentrale-walled-gardens\/\u0022\u003EDezentrale \u201eWalled Gardens\u201c\u003C\/a\u003E\u003C\/cite\u003E\u003C\/blockquote\u003E\u003Cp\u003EDas \u003Ca href=\u0022https:\/\/the-federation.info\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/the-federation.info\/\u0022\u003Efediverse\u003C\/a\u003E hat (wie schon erw\u00e4hnt) bisher einen gro\u00dfartigen Job gemacht und verschiedenste Netzwerke mit den verschiedensten Auspr\u00e4gungen vernetzt! Ich \u003Cs\u003Eglaube\u003C\/s\u003E bin der festen \u00dcberzeugung, dass sich diesmal wirklich das offene Format (\u003Cem\u003EActivityPub\u003C\/em\u003E) durchsetzen wird und Blueskys \u003Cem\u003EAuthenticated Transfer Protocol\u003C\/em\u003E auch in ein paar Monaten oder Jahren keine Rolle spielen wird! \u003C\/p\u003E\u003Cp\u003E\u003Ca href=\u0022https:\/\/twitter.com\/benwerd\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/twitter.com\/benwerd\u0022\u003EBen Werdmuller\u003C\/a\u003E hat eine gesunde Einstellung zu dem Thema:\u003C\/p\u003E\u003Cblockquote class=\u0022wp-block-quote\u0022\u003E\n\u003Cp\u003EI\u2019m so burned out by open source social, but I\u2019m glad to see people throw energy at the problem, even if it\u2019s not how I would have gone about it.\u003C\/p\u003E\n\u003Ccite\u003E\u003Ca href=\u0022https:\/\/twitter.com\/benwerd\/status\/1582554417693270016\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/twitter.com\/benwerd\/status\/1582554417693270016\u0022\u003ETwitter\u003C\/a\u003E\u003C\/cite\u003E\u003C\/blockquote\u003E\u003Cp\u003EMehr hab ich dazu eigentlich nicht zu sagen, au\u00dfer dass wir in der \u003Ca href=\u0022https:\/\/neunetz.fm\/neunetzcast-93-was-wir-unter-dezentralitaet-verstehen-und-was-wir-uns-davon-erhoffen\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/neunetz.fm\/neunetzcast-93-was-wir-unter-dezentralitaet-verstehen-und-was-wir-uns-davon-erhoffen\/\u0022\u003Eaktuellen Folge\u003C\/a\u003E des neunetzcasts sehr ausgiebig \u00fcber genau dieses Problem gesprochen haben!\u003C\/p\u003E\u003Cp\u003E\u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/activitypub\/\u0022\u003E#activitypub\u003C\/a\u003E \u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/bluesky\/\u0022\u003E#bluesky\u003C\/a\u003E \u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/fediverse\/\u0022\u003E#fediverse\u003C\/a\u003E \u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/matrix\/\u0022\u003E#matrix\u003C\/a\u003E \u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/twitter\/\u0022\u003E#twitter\u003C\/a\u003E\u003C\/p\u003E\u003Cp\u003E\u003Ca href=\u0022https:\/\/notiz.blog\/2022\/11\/14\/the-at-protocol\/\u0022\u003Ehttps:\/\/notiz.blog\/2022\/11\/14\/the-at-protocol\/\u003C\/a\u003E\u003C\/p\u003E","contentMap":{"de":"\u003Cp\u003EVor zwei Jahren wollte Twitter in das \u201eDezentrale Netzwerke\u201c-Business einsteigen und gr\u00fcndete eigens daf\u00fcr das \u003Ca href=\u0022https:\/\/notiz.blog\/2019\/12\/13\/twitiverse\/\u0022 data-type=\u0022post\u0022 data-id=\u002218831\u0022\u003EProjekt Bluesky\u003C\/a\u003E. In den folgenden zwei Jahren wurde viel evaluiert und diskutiert, was wohl die beste L\u00f6sung f\u00fcr Twitter sei und wir alle \u003Cem\u003Efieberten\u003C\/em\u003E mit ob es nun \u003Ca href=\u0022https:\/\/www.w3.org\/TR\/activitypub\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/www.w3.org\/TR\/activitypub\/\u0022\u003EActivityPub\u003C\/a\u003E oder doch \u003Ca href=\u0022https:\/\/matrix.org\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/matrix.org\/\u0022\u003EMatrix\u003C\/a\u003E werden w\u00fcrde\u2026 \u003C\/p\u003E\u003Cp\u003EAber das Warten hat ein Ende! \u003Ca href=\u0022https:\/\/blueskyweb.xyz\/blog\/10-18-2022-the-at-protocol\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/blueskyweb.xyz\/blog\/10-18-2022-the-at-protocol\u0022\u003EBluesky hat verk\u00fcndet wie es weiter geht\u003C\/a\u003E!\u003C\/p\u003E\u003Cp\u003E\u003Cstrong\u003ESie entwickeln ein neues Protokoll!\u003C\/strong\u003E\u003C\/p\u003E\u003Cp\u003EDas \u003Cem\u003EAT Protocol\u003C\/em\u003E, kurz f\u00fcr \u003Cem\u003EAuthenticated Transfer Protocol\u003C\/em\u003E!\u003C\/p\u003E\u003Cp\u003EIch hab mir die \u003Ca href=\u0022https:\/\/atproto.com\/guides\/faq\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/atproto.com\/guides\/faq\u0022\u003EFAQ\u003C\/a\u003E mal angeschaut und dort steht warum Bluesky sich gegen ActivityPub entschieden hat:\u003C\/p\u003E\u003Cblockquote class=\u0022wp-block-quote\u0022\u003E\n\u003Cp\u003EAccount portability is the major reason why we chose to build a separate protocol. We consider portability to be crucial because it protects users from sudden bans, server shutdowns, and policy disagreements. Our solution for portability requires both \u003Ca href=\u0022https:\/\/atproto.com\/guides\/data-repos\u0022\u003Esigned data repositories\u003C\/a\u003E and \u003Ca href=\u0022https:\/\/atproto.com\/guides\/identity\u0022\u003EDIDs\u003C\/a\u003E, neither of which are easy to retrofit into ActivityPub. The migration tools for ActivityPub are comparatively limited; they require the original server to provide a redirect and cannot migrate the user\u2019s previous data.\u003C\/p\u003E\n\u003C\/blockquote\u003E\u003Cp\u003EDas erinnert mich ein bisschen an die Subline von meinem \u003Ca href=\u0022https:\/\/pfefferle.dev\/openwebicons\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/pfefferle.dev\/openwebicons\/\u0022\u003EOpenWeb-Icons Font\u003C\/a\u003E:\u003C\/p\u003E\u003Cblockquote class=\u0022wp-block-quote\u0022\u003E\n\u003Cp\u003EWhy \u003Cem\u003EOpenWeb Icons\u003C\/em\u003E? Because \u003Ca href=\u0022https:\/\/fortawesome.com\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/fortawesome.com\/\u0022\u003EFont Awesome\u003C\/a\u003E had no RSS-icon [\u2026]\u003C\/p\u003E\n\u003C\/blockquote\u003E\u003Cp\u003E\u003Cstrong\u003EWeil ActivityPub keine perfekte L\u00f6sung f\u00fcr \u201eAccount portability\u201c hat, bauen sie ein komplett neues Protokoll?\u003C\/strong\u003E\u003C\/p\u003E\u003Cp\u003EActivityPub ist sicherlich nicht \u201efeature complete\u201c, aber ein guter erster Wurf, was das Fediverse erfolgreich bewiesen hat! Warum arbeitet Twitter also lieber an einem eigen Format anstatt mit dem W3C zusammen an ActivityPub v2?\u003C\/p\u003E\u003Cp\u003EWarum macht sich das W3C \u00fcberhaupt noch die M\u00fche \u201eStandards\u201c zu definieren?\u003C\/p\u003E\u003Cp\u003E\u003Cstrong\u003EWegen der Interoperabilit\u00e4t!\u003C\/strong\u003E\u003C\/p\u003E\u003Cp\u003EW\u00fcrde Twitter mit HTTP(S), HTML oder CSS \u00e4hnlich umgehen, w\u00fcrde der Browser einfach leer bleiben, weil das \u0026$%\u00a7\u0026 Internet nur mit einheitlichen Standards funktioniert!\u003C\/p\u003E\u003Cp\u003EUnd das gleiche gilt auch f\u00fcr dezentralte Netze, zumindest wenn sie erfolgreich sein wollen! Dar\u00fcber hab ich tragischerweise schon vor \u003Cstrong\u003E10 Jahren\u003C\/strong\u003E geschrieben!\u003C\/p\u003E\u003Cblockquote class=\u0022wp-block-quote\u0022\u003E\n\u003Cp\u003EDiaspora* wurde kaum \u003Ca href=\u0022https:\/\/web.archive.org\/web\/20130630113539\/http:\/\/blog.diasporafoundation.org\/2012\/08\/27\/announcement-diaspora-will-now-be-a-community-project.html\u0022\u003Ef\u00fcr \u201etot\u201c erkl\u00e4rt\u003C\/a\u003E und schon steht das n\u00e4chste Projekt in den Startl\u00f6chern! \u003Ca href=\u0022https:\/\/web.archive.org\/web\/20190603031810\/https:\/\/tent.io\/\u0022\u003ETent.io\u003C\/a\u003E soll ein protocol for distributed social networking and personal data storage werden. Alles neu, alles anders, alles besser als OStatus, DiSo oder Diaspora*. Aber mal ganz ehrlich\u2026 was haben die Diasporas \u0026 Co. bisher geschaffen? Ziel war es Facebooks \u201eWalled Gardens\u201c aufzubrechen und was kam wirklich dabei rum? Eine ganze Reihe an dezentralen \u201eWalled Gardens\u201c. Na danke!\u003C\/p\u003E\n\u003Ccite\u003E\u003Ca href=\u0022https:\/\/notiz.blog\/2012\/11\/15\/dezentrale-walled-gardens\/\u0022\u003EDezentrale \u201eWalled Gardens\u201c\u003C\/a\u003E\u003C\/cite\u003E\u003C\/blockquote\u003E\u003Cp\u003EDas \u003Ca href=\u0022https:\/\/the-federation.info\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/the-federation.info\/\u0022\u003Efediverse\u003C\/a\u003E hat (wie schon erw\u00e4hnt) bisher einen gro\u00dfartigen Job gemacht und verschiedenste Netzwerke mit den verschiedensten Auspr\u00e4gungen vernetzt! Ich \u003Cs\u003Eglaube\u003C\/s\u003E bin der festen \u00dcberzeugung, dass sich diesmal wirklich das offene Format (\u003Cem\u003EActivityPub\u003C\/em\u003E) durchsetzen wird und Blueskys \u003Cem\u003EAuthenticated Transfer Protocol\u003C\/em\u003E auch in ein paar Monaten oder Jahren keine Rolle spielen wird! \u003C\/p\u003E\u003Cp\u003E\u003Ca href=\u0022https:\/\/twitter.com\/benwerd\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/twitter.com\/benwerd\u0022\u003EBen Werdmuller\u003C\/a\u003E hat eine gesunde Einstellung zu dem Thema:\u003C\/p\u003E\u003Cblockquote class=\u0022wp-block-quote\u0022\u003E\n\u003Cp\u003EI\u2019m so burned out by open source social, but I\u2019m glad to see people throw energy at the problem, even if it\u2019s not how I would have gone about it.\u003C\/p\u003E\n\u003Ccite\u003E\u003Ca href=\u0022https:\/\/twitter.com\/benwerd\/status\/1582554417693270016\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/twitter.com\/benwerd\/status\/1582554417693270016\u0022\u003ETwitter\u003C\/a\u003E\u003C\/cite\u003E\u003C\/blockquote\u003E\u003Cp\u003EMehr hab ich dazu eigentlich nicht zu sagen, au\u00dfer dass wir in der \u003Ca href=\u0022https:\/\/neunetz.fm\/neunetzcast-93-was-wir-unter-dezentralitaet-verstehen-und-was-wir-uns-davon-erhoffen\/\u0022 data-type=\u0022URL\u0022 data-id=\u0022https:\/\/neunetz.fm\/neunetzcast-93-was-wir-unter-dezentralitaet-verstehen-und-was-wir-uns-davon-erhoffen\/\u0022\u003Eaktuellen Folge\u003C\/a\u003E des neunetzcasts sehr ausgiebig \u00fcber genau dieses Problem gesprochen haben!\u003C\/p\u003E\u003Cp\u003E\u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/activitypub\/\u0022\u003E#activitypub\u003C\/a\u003E \u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/bluesky\/\u0022\u003E#bluesky\u003C\/a\u003E \u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/fediverse\/\u0022\u003E#fediverse\u003C\/a\u003E \u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/matrix\/\u0022\u003E#matrix\u003C\/a\u003E \u003Ca rel=\u0022tag\u0022 class=\u0022u-tag u-category\u0022 href=\u0022https:\/\/notiz.blog\/tag\/twitter\/\u0022\u003E#twitter\u003C\/a\u003E\u003C\/p\u003E\u003Cp\u003E\u003Ca href=\u0022https:\/\/notiz.blog\/2022\/11\/14\/the-at-protocol\/\u0022\u003Ehttps:\/\/notiz.blog\/2022\/11\/14\/the-at-protocol\/\u003C\/a\u003E\u003C\/p\u003E"},"to":["https:\/\/www.w3.org\/ns\/activitystreams#Public"],"cc":["https:\/\/www.w3.org\/ns\/activitystreams#Public"],"attachment":[{"type":"Image","url":"https:\/\/notiz.blog\/wp-content\/uploads\/2022\/11\/the-at-protocol.png","mediaType":"image\/png","name":"The Logo of the AT Protocol"}],"tag":[{"type":"Hashtag","href":"https:\/\/notiz.blog\/tag\/activitypub\/","name":"#activitypub"},{"type":"Hashtag","href":"https:\/\/notiz.blog\/tag\/bluesky\/","name":"#bluesky"},{"type":"Hashtag","href":"https:\/\/notiz.blog\/tag\/fediverse\/","name":"#fediverse"},{"type":"Hashtag","href":"https:\/\/notiz.blog\/tag\/matrix\/","name":"#matrix"},{"type":"Hashtag","href":"https:\/\/notiz.blog\/tag\/twitter\/","name":"#twitter"}]}";s:8:"response";a:1:{s:4:"code";i:200;}} \ No newline at end of file diff --git a/tests/test-class-friends-feed-parser-activitypub.php b/tests/test-class-friends-feed-parser-activitypub.php index a7ac7a8..6d1568f 100644 --- a/tests/test-class-friends-feed-parser-activitypub.php +++ b/tests/test-class-friends-feed-parser-activitypub.php @@ -2,6 +2,9 @@ class Test_Friends_Feed_Parser_ActivityPub extends \WP_UnitTestCase { public static $users = array(); + private $friend_id; + private $friend_name; + private $actor; public function set_up() { if ( ! class_exists( '\Friends\Friends' ) ) { @@ -23,14 +26,52 @@ class Test_Friends_Feed_Parser_ActivityPub extends \WP_UnitTestCase { ); add_filter( 'pre_http_request', array( get_called_class(), 'pre_http_request' ), 10, 3 ); + add_filter( 'http_response', array( get_called_class(), 'http_response' ), 10, 3 ); add_filter( 'http_request_host_is_external', array( get_called_class(), 'http_request_host_is_external' ), 10, 2 ); add_filter( 'http_request_args', array( get_called_class(), 'http_request_args' ), 10, 2 ); add_filter( 'pre_get_remote_metadata_by_actor', array( get_called_class(), 'pre_get_remote_metadata_by_actor' ), 10, 2 ); + $user_id = $this->factory->user->create( + array( + 'role' => 'administrator', + ) + ); + wp_set_current_user( $user_id ); + + $this->friend_name = 'Alex Kirk'; + $this->actor = 'https://mastodon.local/users/akirk'; + + $user_feed = \Friends\User_Feed::get_by_url( $this->actor ); + if ( is_wp_error( $user_feed ) ) { + $this->friend_id = $this->factory->user->create( + array( + 'display_name' => $this->friend_name, + 'role' => 'friend', + ) + ); + \Friends\User_Feed::save( + new \Friends\User( $this->friend_id ), + $this->actor, + array( + 'parser' => 'activitypub', + ) + ); + } else { + $this->friend_id = $user_feed->get_friend_user()->ID; + } + + self::$users[ $this->actor ] = array( + 'url' => $this->actor, + 'name' => $this->friend_name, + ); + self::$users['https://mastodon.local/@akirk'] = self::$users[ $this->actor ]; + + _delete_all_posts(); } public function tear_down() { remove_filter( 'pre_http_request', array( get_called_class(), 'pre_http_request' ) ); + remove_filter( 'http_response', array( get_called_class(), 'http_response' ) ); remove_filter( 'http_request_host_is_external', array( get_called_class(), 'http_request_host_is_external' ) ); remove_filter( 'http_request_args', array( get_called_class(), 'http_request_args' ) ); remove_filter( 'pre_get_remote_metadata_by_actor', array( get_called_class(), 'pre_get_remote_metadata_by_actor' ) ); @@ -55,6 +96,18 @@ class Test_Friends_Feed_Parser_ActivityPub extends \WP_UnitTestCase { return $args; } public static function pre_http_request( $preempt, $request, $url ) { + $p = wp_parse_url( $url ); + $cache = __DIR__ . '/fixtures/' . sanitize_title( $p['host'] . '-' . $p['path'] ) . '.response'; + if ( file_exists( $cache ) ) { + return apply_filters( + 'fake_http_response', + unserialize( file_get_contents( $cache ) ), + $p['scheme'] . '://' . $p['host'], + $url, + $request + ); + } + $home_url = home_url(); // Pretend the url now is the requested one. @@ -96,57 +149,58 @@ class Test_Friends_Feed_Parser_ActivityPub extends \WP_UnitTestCase { ); } + public static function http_response( $response, $args, $url ) { + $p = wp_parse_url( $url ); + $cache = __DIR__ . '/fixtures/' . sanitize_title( $p['host'] . '-' . $p['path'] ) . '.response'; + if ( ! file_exists( $cache ) ) { + $headers = wp_remote_retrieve_headers( $response ); + file_put_contents( + $cache, + serialize( + array( + 'headers' => $headers->getAll(), + 'body' => wp_remote_retrieve_body( $response ), + 'response' => array( + 'code' => wp_remote_retrieve_response_code( $response ), + ), + ) + ) + ); + } + return $response; + } + public function test_incoming_post() { $now = time() - 10; $status_id = 123; - $friend_name = 'Alex'; - $actor = 'https://mastodon.local/users/alex'; - - $friend_id = $this->factory->user->create( - array( - 'user_login' => 'alex-mastodon.local', - 'display_name' => $friend_name, - 'role' => 'friend', - ) - ); - \Friends\User_Feed::save( - new \Friends\User( $friend_id ), - $actor, - array( - 'parser' => 'activitypub', - ) - ); - - self::$users[ $actor ] = array( - 'url' => $actor, - 'name' => $friend_name, - ); - self::$users['https://mastodon.local/@alex'] = self::$users[ $actor ]; - $posts = get_posts( array( 'post_type' => \Friends\Friends::CPT, - 'author' => $friend_id, + 'author' => $this->friend_id, ) ); - $this->assertEquals( 0, count( $posts ) ); + $post_count = count( $posts ); + + // Let's post a new Note through the REST API. + $date = gmdate( \DATE_W3C, $now++ ); + $id = 'test' . $status_id; + $content = 'Test ' . $date . ' ' . rand(); $request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/' . get_current_user_id() . '/inbox' ); $request->set_param( 'type', 'Create' ); - $request->set_param( 'id', 'test1' ); - $request->set_param( 'actor', $actor ); - $date = date( \DATE_W3C, $now++ ); - $content = 'Test ' . $date . ' ' . rand(); + $request->set_param( 'id', $id ); + $request->set_param( 'actor', $this->actor ); + $request->set_param( 'object', array( 'type' => 'Note', - 'id' => 'test1', - 'attributedTo' => $actor, + 'id' => $id, + 'attributedTo' => $this->actor, 'content' => $content, - 'url' => 'https://mastodon.local/users/alex/statuses/' . ( $status_id++ ), + 'url' => 'https://mastodon.local/users/akirk/statuses/' . ( $status_id++ ), 'published' => $date, ) ); @@ -157,28 +211,31 @@ class Test_Friends_Feed_Parser_ActivityPub extends \WP_UnitTestCase { $posts = get_posts( array( 'post_type' => \Friends\Friends::CPT, - 'author' => $friend_id, + 'author' => $this->friend_id, ) ); - $this->assertEquals( 1, count( $posts ) ); + $this->assertEquals( $post_count + 1, count( $posts ) ); $this->assertEquals( $content, $posts[0]->post_content ); - $this->assertEquals( $friend_id, $posts[0]->post_author ); + $this->assertEquals( $this->friend_id, $posts[0]->post_author ); + + // Do another test post, this time with a URL that has an @-id. + $date = gmdate( \DATE_W3C, $now++ ); + $id = 'test' . $status_id; + $content = 'Test ' . $date . ' ' . rand(); $request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/' . get_current_user_id() . '/inbox' ); $request->set_param( 'type', 'Create' ); - $request->set_param( 'id', 'test1' ); - $request->set_param( 'actor', 'https://mastodon.local/@alex' ); - $date = date( \DATE_W3C, $now++ ); - $content = 'Test ' . $date . ' ' . rand(); + $request->set_param( 'id', $id ); + $request->set_param( 'actor', 'https://mastodon.local/@akirk' ); $request->set_param( 'object', array( 'type' => 'Note', - 'id' => 'test2', - 'attributedTo' => 'https://mastodon.local/@alex', + 'id' => $id, + 'attributedTo' => 'https://mastodon.local/@akirk', 'content' => $content, - 'url' => 'https://mastodon.local/users/alex/statuses/' . ( $status_id++ ), + 'url' => 'https://mastodon.local/users/akirk/statuses/' . ( $status_id++ ), 'published' => $date, ) ); @@ -189,12 +246,64 @@ class Test_Friends_Feed_Parser_ActivityPub extends \WP_UnitTestCase { $posts = get_posts( array( 'post_type' => \Friends\Friends::CPT, - 'author' => $friend_id, + 'author' => $this->friend_id, ) ); - $this->assertEquals( 2, count( $posts ) ); + $this->assertEquals( $post_count + 2, count( $posts ) ); $this->assertEquals( $content, $posts[0]->post_content ); - $this->assertEquals( $friend_id, $posts[0]->post_author ); + $this->assertEquals( $this->friend_id, $posts[0]->post_author ); + } + + public function test_incoming_announce() { + $now = time() - 10; + $status_id = 123; + + self::$users['https://notiz.blog/author/matthias-pfefferle/'] = array( + 'url' => 'https://notiz.blog/author/matthias-pfefferle/', + 'name' => 'Matthias Pfefferle', + ); + + $posts = get_posts( + array( + 'post_type' => \Friends\Friends::CPT, + 'author' => $this->friend_id, + ) + ); + + $post_count = count( $posts ); + + $date = gmdate( \DATE_W3C, $now++ ); + $id = 'test' . $status_id; + + $object = 'https://notiz.blog/2022/11/14/the-at-protocol/'; + + $request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/' . get_current_user_id() . '/inbox' ); + $request->set_param( 'type', 'Announce' ); + $request->set_param( 'id', $id ); + $request->set_param( 'actor', $this->actor ); + $request->set_param( 'published', $date ); + $request->set_param( 'object', $object ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 202, $response->get_status() ); + + $p = wp_parse_url( $object ); + $cache = __DIR__ . '/fixtures/' . sanitize_title( $p['host'] . '-' . $p['path'] ) . '.response'; + $this->assertFileExists( $cache ); + + $object = json_decode( wp_remote_retrieve_body( unserialize( file_get_contents( $cache ) ) ) ); + + $posts = get_posts( + array( + 'post_type' => \Friends\Friends::CPT, + 'author' => $this->friend_id, + ) + ); + + $this->assertEquals( $post_count + 1, count( $posts ) ); + $this->assertStringContainsString( 'Dezentrale Netzwerke', $posts[0]->post_content ); + $this->assertEquals( $this->friend_id, $posts[0]->post_author ); + } }