Hi folks,
I recently switched over from Ghost to WF and decided to also use it for a private community that we set up to replace Facebook Groups. Some context about me and ActivityPub. I built one of the first ActivityPub plugins for Ghost back in 2023 which became obsolete once they finally added support in Ghost 6 last year. I ended up writing my own AP implementation because the NodeJS libraries at the time were overkill and brought in too many unnecessary couplings or were not conformant. (Go is so much nicer than NodeJS).
At any rate, I prefer how minimal WF is and I don’t need or want the ActivityPub “inbox” that Ghost provides.
While tweaking WF’s source code for our community’s needs, I discovered and fixed some bugs and security issues regarding ActivityPub behavior and wanted to submit them upstream. A lot of these issues were discovered while federating with Mastodon, Mbin, and GoToSocial.
My bug fixes are a number of small things so I would be happy to open separate threads for each. Let me know how you’d like me to proceed:
WriteAs Web Core:
-
Federated activities reused their object’s id → Each activity gets a distinct id (per AP 2.0 spec).
- There’s an existing source code comment/change regarding Pleroma but only for Delete activities, it needs the id for all activities.
-
ActivityPub key generation relies on OpenSSL binary → Now uses
crypto/rsadirectly in the source code instead.- I use Docker and didn’t configure openssl correctly. WF silently failed to generate keys (required by GoToSocial and “strict” Mastodon) breaking federation.
-
NewRemoteActorissues a plain unsigned GET response → Now signs actor requests- Mastodon/GtS authorized-fetch instances answer 401 and I could not follow my blog from hachyderm’s instance.
-
DecodePrivateKeychecks whetherpem.Decodereturned a nil block and then dereferences that same nil block to format the error causing a panic. → Fixed by checking for nil before formatting.
WriteFreely:
-
log.Error("Target POST URL is empty! Person: %+v", p) — %+vprints WriteFreely’s ActivityPub signing key which gets written to logs. → Now only logsp.IDfor Person objects. -
WF fails to respect unfollow requests (sad path) →
acceptAndPersistFollowreturned beforeDELETE FROM remotefollows, so a delivery failure continues to post to someone who unfollowed. → Fixed by deleting the follow from the DB before the response is sent back so that remote failures don’t interrupt the unfollow logic on WF. -
Similar to above, the “Unfollow” request was incorrectly mapped to the “unfollow” object instead of the “unfollow”'s actor. → Fixed by resolving the actor from the
Followobject. -
handleFetchCollectionInboxwould write the follow only after theAccept’s serialize-and-deliver block, meaning failedAcceptrequests were never written to the database (the remote software assumed it was following when it wasn’t). → Fixed by moving theisFollow transactionabove the serialize-and-deliver block so that harmless errors don’t break follows. -
Fixed a webfinger cache poisoning bug.
GetProfileURLFromHandleINSERTed a failed webfinger result as aremoteusersrow with an emptyactor_id. →RemoteLookupreturns an error now instead of writing an emptyactor_idstring to the database. Particularly impactful due to once the signed actor get request bug above (but not mitigated entirely after fixing the signed GET bug)- Affects the
rel=meverification as well (Eg: Put a fediverse handle instead of a URL in the blog’s verification links and it’s supposed to normalize into a profile URL but doesn’t)
- Affects the
Btw, the GitHub repo’s README link to the contribution guidelines are broken (404): writefreely/CONTRIBUTING.md at develop · writefreely/writefreely · GitHub
And the contributor agreement also 404s: http://todo.musing.studio/L1