Automattic / wordpress-activitypub

ActivityPub for WordPress
https://wordpress.org/plugins/activitypub/
MIT License
485 stars 73 forks source link

Block “Fediverse Followers” crashes page/blog #571

Closed cybeardjm closed 10 months ago

cybeardjm commented 10 months ago

Quick summary

Had a published page to publicize the fedified status of both of my blogs, created some time ago. Since then, the plugin was updated to latest version 1.1.0, then 1.2.0.

When visiting the page, it’s now broken or not available due to a critical error on the blog. When trying to create a new post/page with the block, "This block has encountered an error and cannot be previewed." and draft can’t be saved. When trying to edit a post/page containing the block, critical error...

Steps to reproduce

1 - Create a new post. 2 - Add "Fediverse Followers" block.

What you expected to happen

Block doesn't crash page/blog when viewed, allows editing, etc.

What actually happened

The PHP error log shows multiple (many!) errors like this one (real domain name replaced by (domain) _below):

[13-Nov-2023 23:02:18 UTC] PHP Fatal error: Uncaught TypeError: ltrim(): Argument #1 ($string) must be of type string, array given in /srv/data/web/vhosts/(domain)/htdocs/wp-includes/formatting.php:4494 Stack trace:

0 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/formatting.php(4494): ltrim()

1 /srv/data/web/vhosts/(domain)/htdocs/wp-content/plugins/activitypub/includes/class-blocks.php(143): esc_url()

2 /srv/data/web/vhosts/(domain)/htdocs/wp-content/plugins/activitypub/includes/class-blocks.php(119): Activitypub\Blocks::render_follower()

3 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/class-wp-block.php(258): Activitypub\Blocks::render_follower_block()

4 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/blocks.php(1484): WP_Block->render()

5 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/blocks.php(1522): render_block()

6 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/class-wp-hook.php(324): do_blocks()

7 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/plugin.php(205): WP_Hook->apply_filters()

8 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php(620): apply_filters()

9 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php(451): WP_REST_Revisions_Controller->prepare_item_for_response()

10 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php(253): WP_REST_Autosaves_Controller->prepare_item_for_response()

11 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/rest-api/class-wp-rest-server.php(1193): WP_REST_Autosaves_Controller->create_item()

12 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/rest-api/class-wp-rest-server.php(1041): WP_REST_Server->respond_to_request()

13 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/rest-api/class-wp-rest-server.php(431): WP_REST_Server->dispatch()

14 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/rest-api.php(424): WP_REST_Server->serve_request()

15 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/class-wp-hook.php(324): rest_api_loaded()

16 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters()

17 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/plugin.php(565): WP_Hook->do_action()

18 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/class-wp.php(418): do_action_ref_array()

19 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/class-wp.php(813): WP->parse_request()

20 /srv/data/web/vhosts/(domain)/htdocs/wp-includes/functions.php(1336): WP->main()

21 /srv/data/web/vhosts/(domain)/htdocs/wp-blog-header.php(16): wp()

22 /srv/data/web/vhosts/(domain)/htdocs/index.php(17): require('...')

23 {main} thrown in /srv/data/web/vhosts/(domain)/htdocs/wp-includes/formatting.php on line 4494

Impact

One

Available workarounds?

No and the platform is unusable

Logs or notes

No response

pfefferle commented 10 months ago

Do you see the same issue when paging through the followers list in wp-admin?

pfefferle commented 10 months ago

Respectively is it possible for you to check (and maybe provide me) the url field for that follower or can you maybe provide me the profile-URL (privately) that I can debug it?

cybeardjm commented 10 months ago

Oh interesting...

Blog 1 = WWW

When checking the followers list in WP-Admin, I get Author Followers Your author profile currently has 0 followers. Reflected (logical) on @@.*** although I had about 50 some time ago... It seems the post-type " ap_follower " in the DB has disappeared too... (tried to deactivate/reactivate AP plugin, same)

Well, now that the number is 0, I can open or edit the page again... https://www.didiermary.fr/blog-fediverse/ (the block should appear under "Fediverse Followers" if not 0)

=> https://www.didiermary.fr/wp-json/activitypub/1.0/users/1/outbox looks quite empty (except posts)

Blog 2 = AMF Still have " ap_follower " in DB (value = 64) for @ @.*** But page still impossible to edit/preview/publish... => fatal error => https://amf.didiermary.fr/wp-json/activitypub/1.0/users/1/outbox DJM

pfefferle commented 10 months ago

Do you use DB cleanup plugins?

cybeardjm commented 10 months ago

Yes, I do. But in manual mode only. "ap_follower" is back @ 0 for now, after I restarted a lot of stuff. It will probably populate over time. https://www.didiermary.fr/wp-json/activitypub/1.0/users/1/outbox is still a bit empty...

pfefferle commented 10 months ago

@cybeardjm this is paged, so it shows only the last 10 posts, but it has 78 pages.

What cleanup plugin do you use?

cybeardjm commented 10 months ago

Yes I know, and then each page = 10 posts... Rechecked, and it seems all data now appear, e.g. context, etc.

Plugin = Meow Database cleaner. But, IMHO, the reason is this: I've been testing with various cache plugins (1 by 1), and the last one I tested, before I noticed this, was Docket Cache – Object Cache Accelerator. It's now removed, I deactivated/reactivated the AP plugin. The "AP-follower" post-type is back, still @ 0.

This doesn't change the fatal error on blog 2...

cybeardjm commented 10 months ago

Matthias, seems you just started following my WWW blog 2023-11-28 18:10:45as you just appeared in the admin and on the page. Just refollowed my blog from my masto.ai profile, and I just appeared too. And no crash!

cybeardjm commented 10 months ago

OK, just found why the block crashed on AMF...

A few days ago, I tested Bridgy.Fed, to connect a test blog ( https://djm.didiermary.fr) to the Fediverse, instead of using ActivityPub directly. Just in case, profile is here: https://fed.brid.gy/web/djm.didiermary.fr

It worked globally and you can find it here: @ teddy @ djm.didiermary.fr (yes I used an alias via class="u-url" href= "acct:teddy @..." ) It allowed my test blog to follow (via IndieAuth) and be followed. I followed both of my blogs' author on AMF & WWW .

As my Followers list disappeared on WWW , I decided to check on AMF what it looked like. Was still there, although couldn't use the block.

And I know why: in the list of AP followers, for the one based on Bridgy Fed, the URL field didn't contain @ , but the word "Array" as a link to the local site (forgot to copy the exact URL). After I deleted this "follower", everything worked fine again. The main data in the list: Name = You can call me Teddy (see homepage, for origin of this in the h-card) Username = djm.didiermary.fr (the "real" username for the instance, "Teddy" being an alias) URL = Array + local link

This explains why it worked again on WWW: as the crash I had while testing, wiped out the list of followers, "Array" was gone... ;-)

1 - this is probably more a problem with Bridgy Fed in how it declares the URL for a follower.

  1. in the meantime, just in case other "users" like me do the same thing, you might add a test to avoid any "Array" entry trying to appear in the block (there's no problem in the Followers list in the back office)

Hope this helps.

snarfed commented 10 months ago

Looks like @cybeardjm is right, the AP actor https://fed.brid.gy/djm.didiermary.fr does have a multiply valued url field. This is because https://djm.didiermary.fr/ has two u-urls, and Bridgy Fed propagates both of them into the AP actor. It looks like:

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/v1"
  ],
  "id": "https://fed.brid.gy/djm.didiermary.fr",
  "url": [
    "https://fed.brid.gy/r/https://djm.didiermary.fr/",
    "acct:teddy@djm.didiermary.fr"
  ]
  "..."
}

I'll grant that this is less common, but it's definitely valid AS2. Note the examples in https://www.w3.org/TR/activitystreams-vocabulary/#dfn-url and that it's not marked Functional. From https://www.w3.org/TR/activitystreams-vocabulary/#properties :

Properties marked as being "Functional" can have only one value. Items not marked as "Functional" can have multiple values.

@pfefferle, do you need any help fixing this on the plugin's side so that it supports multiply valued urls?

cybeardjm commented 10 months ago

Thx @snarfed - the alias (acct:) is a good solution to avoid having to exist as (longdomain) @ (longdomain). I saw it, I used it... ;-) and it worked...

pfefferle commented 10 months ago

@snarfed thanks, I know about it, but had hoped that it would simply always be used as string 🙄

I hoped to avoid checking for string, Link Object, array of strings and array of Link Objects 😔

pfefferle commented 10 months ago

Just out of curiosity... is there a benefit of adding the acct URI @snarfed ?

snarfed commented 10 months ago

Fair question! I'm not doing it deliberately, I just pass through everything in u-url.

snarfed commented 10 months ago

@pfefferle @cybeardjm I've updated Bridgy Fed to omit these acct: URIs. url will still be an array for some actors, both BF and non-BF, eg https://fed.brid.gy/tantek.com, so @pfefferle you may still want to handle it, but in the common case, including https://fed.brid.gy/djm.didiermary.fr , it's now a single string.

pfefferle commented 10 months ago

@snarfed I will fix it and I understand your idea behind that, but I had another look at the spec and it describes the URL filed like followed:

Identifies one or more links to representations of the object 

So in this case the URL should link to different representations of Tanteks Actor Profile and not to his other social network profiles?!?

In my understanding, it shouldn't matter which profile from the list I use, it should always represent the Actor tantek.com, but in the case of fed.brid.gy, I can only use the first one for ActivityPub (get profile informations via content negotiation for example)!

I would recommend using the attachment (Link) in that case.

snarfed commented 10 months ago

Hmm! https://www.w3.org/TR/activitystreams-vocabulary/#dfn-url , right? I don't think "representations" necessarily means AS2 actors. The example URLs in that section point to .pdf and .html URLs, which presumably don't serve AS2.

pfefferle commented 10 months ago

True, but still more a rel="alternate" instead of a rel="me"!?!

snarfed commented 10 months ago

Not sure I follow. Where are the rels here? On the source web site? What are you proposing I do with them?

pfefferle commented 10 months ago

The "rel" thing was just meant as an example to emphasize my point (which probably didn't work out so well).

What I meant to say is that the spec says that the URL is used to have different representations of an object (similar to rel="alternate" for HTTP and HTML), but fed.brid.gy uses all kinds of other URLs that are also about or from the person (re-use the rel="me").

snarfed commented 10 months ago

True! I would argue those two ideas are more similar than different. Eg my Facebook profile https://www.facebook.com/snarfed.org is about or from me, and it also seems like another "representation of the object" of my AP actor https://fed.brid.gy/snarfed.org , even if that Facebook URL doesn't serve AS2.

Regardless, the issue here for @cybeardjm at least is fixed. I think I have seen some other fediverse servers serve array-valued urls though, so independent of Bridgy Fed, you may want to handle that sooner or later, if only to not crash. 😁

If you want some resolution on the spec interpretation here, feel free to file an issue on https://github.com/w3c/activitystreams/issues ! Evan has been triaging those issues regularly, he'd get to it soon.

snarfed commented 3 months ago

Hi all! We're seeing this again on @starrwulfe's site. Here's the full error and stack trace and activity below; I'll let @starrwulfe post details on his site, WP and plugin versions, etc.

500 Server Error: Internal Server Error for url: https://starrwulfe.xyz/wp-json/activitypub/1.0/actors/1/inbox ;

{
  "code": "internal_server_error",
  "message": "...",
  "file": "/var/www/wordpress/wp-includes/formatting.php",
  "line": 4494
}},"additional_errors":[]}

<p>There has been a critical error on this website.</p><p><a href=\"https://wordpress.org/documentation/article/faq-troubleshooting/\">Learn more about troubleshooting WordPress.</a></p>","data":{"status":500,"error":{"type":1,"message":"Uncaught TypeError: ltrim(): Argument #1 ($string) must be of type string, array given in /var/www/wordpress/wp-includes/formatting.php:4494
Stack trace:
#0 /var/www/wordpress/wp-includes/formatting.php(4494): ltrim()
#1 /var/www/wordpress/wp-includes/formatting.php(4620): esc_url()
#2 /var/www/wordpress/wp-includes/formatting.php(4602): sanitize_url()
#3 /var/www/wordpress/wp-content/plugins/activitypub/includes/collection/class-interactions.php(60): esc_url_raw()
#4 /var/www/wordpress/wp-content/plugins/activitypub/includes/handler/class-create.php(61): Activitypub\\Collection\\Interactions::add_comment()
#5 /var/www/wordpress/wp-includes/class-wp-hook.php(324): Activitypub\\Handler\\Create::handle_create()
#6 /var/www/wordpress/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters()
#7 /var/www/wordpress/wp-includes/plugin.php(517): WP_Hook->do_action()
#8 /var/www/wordpress/wp-content/plugins/activitypub/includes/rest/class-inbox.php(136): do_action()
#9 /var/www/wordpress/wp-includes/rest-api/class-wp-rest-server.php(1230): Activitypub\\Rest\\Inbox::user_inbox_post()
#10 /var/www/wordpress/wp-includes/rest-api/class-wp-rest-server.php(1063): WP_REST_Server->respond_to_request()
#11 /var/www/wordpress/wp-includes/rest-api/class-wp-rest-server.php(439): WP_REST_Server->dispatch()
#12 /var/www/wordpress/wp-includes/rest-api.php(428): WP_REST_Server->serve_request()
#13 /var/www/wordpress/wp-includes/class-wp-hook.php(324): rest_api_loaded()
#14 /var/www/wordpress/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters()
#15 /var/www/wordpress/wp-includes/plugin.php(565): WP_Hook->do_action()
#16 /var/www/wordpress/wp-includes/class-wp.php(418): do_action_ref_array()
#17 /var/www/wordpress/wp-includes/class-wp.php(813): WP->parse_request()
#18 /var/www/wordpress/wp-includes/functions.php(1336): WP->main()
#19 /var/www/wordpress/wp-blog-header.php(16): wp()
#20 /var/www/wordpress/index.php(17): require('...')
#21 {main}
  thrown

Here's the activity that was delivered:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Create",
  "id": "https://bsky.brid.gy/convert/ap/at://did:plc:ke5adm7cnbxc5ek34fsrt5bt/app.bsky.feed.post/3kwdw6vbjsc2f#bridgy-fed-create",
  "actor": "https://bsky.brid.gy/ap/did:plc:ke5adm7cnbxc5ek34fsrt5bt",
  "published": "2024-07-03T03:00:53.419317+00:00",
  "to": ["https://www.w3.org/ns/activitystreams#Public"]
  "object": {
    "type": "Note",
    "id": "https://bsky.brid.gy/convert/ap/at://did:plc:ke5adm7cnbxc5ek34fsrt5bt/app.bsky.feed.post/3kwdw6vbjsc2f",
    "url": "https://fed.brid.gy/r/https://bsky.app/profile/did:plc:ke5adm7cnbxc5ek34fsrt5bt/post/3kwdw6vbjsc2f",
    "attributedTo": "https://bsky.brid.gy/ap/did:plc:ke5adm7cnbxc5ek34fsrt5bt",
    "inReplyTo": "https://starrwulfe.xyz/notes/2024/07/593c2fce1a/",
    "content": "<p>This is a reply from Bsky. If all goes well, it should be routed back into the <a href=\"https://bsky.brid.gy/hashtag/fediverse\">#fediverse</a> and also picked up by the Friends plugin and as a comment on the blog page that originated it (at the <a href=\"https://starrwulfe.xyz/b/3bVT\">starrwulfe.xyz/b/3bVT</a> link above)<br><br><a title=\"This is a test note from my blog ...\" href=\"https://starrwulfe.xyz/b/3bVT\">This is a test note from my bl...</a></p>",
    "contentMap": {
      "en": "<p>This is a reply from Bsky. If all goes well, it should be routed back into the <a href=\"https://bsky.brid.gy/hashtag/fediverse\">#fediverse</a> and also picked up by the Friends plugin and as a comment on the blog page that originated it (at the <a href=\"https://starrwulfe.xyz/b/3bVT\">starrwulfe.xyz/b/3bVT</a> link above)<br><br><a title=\"This is a test note from my blog ...\" href=\"https://starrwulfe.xyz/b/3bVT\">This is a test note from my bl...</a></p>"
    }
    "content_is_html": true,
    "published": "2024-07-03T03:00:50.936Z",
    "tag": [
      {
        "type": "Hashtag",
        "name": "#fediverse",
        "href": "https://bsky.brid.gy/hashtag/fediverse"
      },
      {
        "url": "https://starrwulfe.xyz/b/3bVT",
        "type": "Article",
        "name": "starrwulfe.xyz/b/3bVT"
      },
      {
        "type": "Mention",
        "href": "https://starrwulfe.xyz/author/starrwulfe/"
      }
    ],
    "to": ["https://www.w3.org/ns/activitystreams#Public"],
    "cc": [
      "https://starrwulfe.xyz/author/starrwulfe/",
      "https://starrwulfe.xyz/wp-json/activitypub/1.0/actors/1/followers",
      "https://www.w3.org/ns/activitystreams#Public"
    ],
  },
}
snarfed commented 3 months ago

Ah, looks like root cause may be the same, https://bsky.brid.gy/ap/did:plc:ke5adm7cnbxc5ek34fsrt5bt has an array-valued url field:

  "url": [
    "https://bsky.brid.gy/r/https://bsky.app/profile/starrwulfe.xyz",
    "https://starrwulfe.xyz/"
  ]
StarrWulfe commented 3 months ago

I'm on ActivityPub Plugin 2.5.0, Friends 2.9.3, running Wordpress 6.5.5.