dahlia / fedify

ActivityPub server framework in TypeScript
https://fedify.dev/
MIT License
327 stars 13 forks source link

Public Key Response Handling And Just Overall Thoughts #21

Closed zach-planet-nine closed 3 months ago

zach-planet-nine commented 3 months ago

First let me start by saying great job on this repo. Having spent the last two days with it and ActivityPub in general, I'm impressed with how much work is here, and what it's capable of given how convoluted ActivityPub is (not a knock on the protocol, anything that's trying to cover a big use case is going to be hard to grok).

I've got my server servin', and am able to send a Follow activity to a user on a Mastodon instance. That generates a GET request back to my server to get the actor's publicKey, and for the life of me I can't figure out what I'm supposed to send back. I have the following:

const jsonLd = {
                "@context": "https://www.w3.org/ns/activitystreams",
                "id": new URL("https://definitely-quality-amoeba.ngrok-free.app/users/planet-nine-test#main-key"),
                type: "Person",
                "publicKey": {
                    "id": new URL("https://definitely-quality-amoeba.ngrok-free.app/users/planet-nine-test#main-key"),
                    "owner": "https://definitely-quality-amoeba.ngrok-free.app/users/planet-nine-test",
                    publicKeyPem: pemPublicKey
                }
        };
        return new Response(JSON.stringify(jsonLd));

but still get the error from Mastodon that Unable to fetch key JSON at https://definitely-quality-amoeba.ngrok-free.app/users/planet-nine-test#main-key.

Figuring out what this should would help me in the short term, but in the long term I think this should be abstracted more away from the implementer. I think that's your intent with the federation callbacks, but it looks like maybe they're only partially implemented? There's setKeyPairDispatcher, but as far as I can tell, the only place it's called is in getKeyPairFromHandle in the context middleware, and when invoked it doesn't even return the publicKey.

Which brings me to my larger thought. You're sort of sitting in between ease of use, and extensibility right now, and I think you should pick one and go more in that direction. Since your goal for this repo is: "It aims to eliminate the complexity and redundant boilerplate code when building a federated server app" I'd pick the former. Fedify should just handle key requests for me imo. In fact I'd go so far as to say Fedify should just handle all the crypto stuff without me having to think about it since letting people do their own crypto stuff is dangerous.

If you wanted to go the other way, I'd suggest losing the dependence on DenoKV, and thus Deno itself, and build server bindings, and DB bindings.

Anyway, just my 2 cents. If I can figure out the publicKey response I'll do another PR for what I have. My plan is to build a minimal implementation for all the Fediverse types (micro-blog, friendster, music, etc) so people can see how to follow and post to them via Fedify. My plan is to use https://github.com/planet-nine-app/sessionless, which is an identity system I've been working on so that people don't have to deal with email/password.

Again nice work on this. It's been very helpful in getting started.

zach-planet-nine commented 3 months ago

So I got a little bit further, and finally found the federation.handle function. I haven't gotten it to work, but that's the function you want to highlight to make this easier. Now I'm responding to a web finger request and that's failing for some reason.

I'll keep banging away, but if you have code that successfully follows and posts to mastodon, I'd love to see it.

dahlia commented 3 months ago

First of all, I finally wrote a step-by-step tutorial for Fedify yesterday. Until now, the documentation was scattered like puzzle pieces, making it hard to see the big picture. I believe this tutorial will show you the whole picture.

zach-planet-nine commented 3 months ago

Nice tutorial! It works with Mastodon (mastodon.social) so long as preferredUsername is the same as name, and handle. When Mastodon searches for an actor it does a follow up web finger request with the preferredUsername, and that fails with Fedify for some reason. If I figure out why, I'll fix it up.

But I can't go the other direction, namely following someone on Mastodon from my Edify server. I'm getting a verification failed message so guessing it's something in the crypto chain. I'll keep trying but might have to put this aside for a couple of days.

dahlia commented 3 months ago

If you show me your code, I might be able to help.

zach-planet-nine commented 3 months ago

Hoo boy! I finally got this to work. So I ran into a bunch of stuff, but I think the only real problems were that the Deno server was truncating #main-key from the url, and handle in the middleware doesn't have a handler for key requests (a search for #main-key shows that it's set, but never looked for). Don't know what's up with Deno server truncating the url. That seems like a bad bug.

The second thing was there seems to be no documentation on the internet on what you're supposed to send back for the key request. Turns out it's just a person object with the CryptographicKey instead of a key href. Seems obvious now, but that took a while to figure out. I wonder if we can send the CryptographicKey on the initial Activity. I might try that before changing things.

Btw, is there a way to clear the outbox? Mine's filled with failed Follow Activities that keep failing.

Ok, so gonna clean up, and submit a PR for the follow example, and what I need to change to get it working, but please if I've missed anything around the key response just let me know.

dahlia commented 3 months ago

So I ran into a bunch of stuff, but I think the only real problems were that the Deno server was truncating #main-key from the url, and handle in the middleware doesn't have a handler for key requests (a search for #main-key shows that it's set, but never looked for). Don't know what's up with Deno server truncating the url. That seems like a bad bug.

Actually, URI fragments are not supposed to be sent to the server. Therefore, that behavior is not a bug in Deno.

I wonder if we can send the CryptographicKey on the initial Activity.

I don't think it's possible, because Mastodon and other implementations rely on the HTTP Signatures spec, and the key exchange in HTTP Signatures doesn't work that way.

Btw, is there a way to clear the outbox? Mine's filled with failed Follow Activities that keep failing.

When you say outbox, are you referring to the place where activities that are sent to your server from a peer server like Mastodon are piled up? If the peer server keeps sending you the same activity, it's most likely due to a server error in the inbox. The side sending activities is supposed to retry if the receiving side doesn't receive them properly due to a server error. If you keep getting server errors during development, you might receive the same activity over and over again even after the server is fixed, which is a common occurrence during ActivityPub development.

zach-planet-nine commented 3 months ago

Actually, URI fragments are not supposed to be sent to the server. Therefore, that behavior is not a bug in Deno.

TIL

When you say outbox, are you referring to the place where activities that are sent to your server from a peer server like Mastodon are piled up? If the peer server keeps sending you the same activity, it's most likely due to a server error in the inbox. The side sending activities is supposed to retry if the receiving side doesn't receive them properly due to a server error. If you keep getting server errors during development, you might receive the same activity over and over again even after the server is fixed, which is a common occurrence during ActivityPub development.

I think this is what was happening. Probably not something I'll ever notice outside of developing.

This is cool, now that I've got it working and know more about what's going on. I'll clean up what I have and add some more Mastodon functions and make a PR if you're into it.