From 75cf0d4469a25d84e1959a312627b5078b144933 Mon Sep 17 00:00:00 2001 From: Miguel Michelson Martinez Date: Tue, 12 Sep 2023 03:05:27 -0300 Subject: [PATCH] discovery & webfinger guides --- guides/discovery-rails.md | 75 +++++++++++++++++++++++++++++++++++++++ guides/webfinger.md | 69 +++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 guides/discovery-rails.md create mode 100644 guides/webfinger.md diff --git a/guides/discovery-rails.md b/guides/discovery-rails.md new file mode 100644 index 0000000..4030cac --- /dev/null +++ b/guides/discovery-rails.md @@ -0,0 +1,75 @@ +Registering with another ActivityPub server, often called "following" in the context of social interactions, typically involves a few steps: + +1. **Discovering the Actor on the remote server**: Before you can follow someone (or some entity), you need to discover their unique ActivityPub ID (usually a URL). + +2. **Sending a `Follow` activity**: To start the following process, your server sends a `Follow` activity to the remote server. + +3. **Remote server responds**: The remote server then acknowledges this with an `Accept` or `Reject` activity. + +To implement this in a Rails context, you'd likely want some combination of models, controllers, and views (forms). Here's a basic guide: + +### 1. Discovering the Actor: + +#### a. Form to input Actor ID: + +You can create a simple form where a user can paste or type in the ActivityPub ID of the actor they want to follow. + +```erb +<%= form_with(url: discover_actor_path, method: :post) do |f| %> + <%= f.label :actor_id, "Enter Actor's ActivityPub ID" %> + <%= f.text_field :actor_id %> + <%= f.submit "Discover" %> +<% end %> +``` + +### 2. Sending a `Follow` activity: + +#### a. Displaying the discovered Actor: + +Once you've fetched the Actor's data (like their name, avatar, summary, etc.), present it to the user and offer an option to follow. + +```erb +<% if @actor %> +

<%= @actor.name %>

+ <%= image_tag @actor.avatar_url %> +

<%= @actor.summary %>

+ <%= button_to "Follow", follow_actor_path(actor_id: @actor.id), method: :post %> +<% end %> +``` + +#### b. Sending the `Follow` Activity: + +When the "Follow" button is pressed, construct and send a `Follow` activity to the remote server. + +```ruby +def follow + actor_id = params[:actor_id] + # Construct your `Follow` activity + activity = { + '@context': 'https://www.w3.org/ns/activitystreams', + 'type': 'Follow', + 'actor': current_user.activitypub_id, + 'object': actor_id + } + # Send this to the remote server + # ... +end +``` + +### 3. Handling the remote server's response: + +You'll want to handle incoming activities (like `Accept` or `Reject` in response to your `Follow`). If the remote actor accepts, store this relationship in your database, perhaps with a `Following` model. + +### Tips: + +1. **Webfinger**: Some platforms use Webfinger to make discovering users easier. Instead of needing the full ActivityPub ID, you can type in a username like `@user@domain.com`, and the server translates that into an ActivityPub ID. + +2. **Security**: Always validate incoming and outgoing data. ActivityPub deals with external servers, so there's an inherent risk. + +3. **Feedback for Users**: Give feedback to your users. Let them know when the follow request has been sent, and again when it's been accepted or rejected. + +4. **Idempotency**: If a user tries to follow an actor they're already following, handle this gracefully. Maybe send an `Undo` `Follow` activity or simply notify the user they're already following the actor. + +5. **Error Handling**: The remote server might not be available, or there might be other issues with the `Follow` request. Handle these gracefully with appropriate error messages. + +Following this guide, you can create a simple yet functional interface for your Rails app's users to follow actors on remote ActivityPub servers. \ No newline at end of file diff --git a/guides/webfinger.md b/guides/webfinger.md new file mode 100644 index 0000000..b9bb00a --- /dev/null +++ b/guides/webfinger.md @@ -0,0 +1,69 @@ +Let's outline a basic Webfinger implementation for our Rails context: + +### 1. Webfinger Route + +First, you need to add a route that will respond to Webfinger queries: + +```ruby +# config/routes.rb +get '/.well-known/webfinger', to: 'webfinger#show' +``` + +### 2. Webfinger Controller + +Then, create a controller that handles the Webfinger requests: + +```ruby +# app/controllers/webfinger_controller.rb +class WebfingerController < ApplicationController + def show + account = params[:resource].sub('acct:', '') + + user = User.find_by(webfinger_account: account) + + if user + render json: { + subject: "acct:#{user.webfinger_account}", + links: [ + { + rel: 'self', + type: 'application/activity+json', + href: user_activitypub_url(user) + } + ] + } + else + render status: :not_found + end + end +end +``` + +### 3. User Model + +You might need a method or attribute for the user's ActivityPub URL. Here's a simple example, assuming `User` has an `username` field: + +```ruby +# app/models/user.rb +class User < ApplicationRecord + def webfinger_account + "#{username}@#{Rails.application.routes.default_url_options[:host]}" + end + + def activitypub_url(user) + "https://your-domain.com/activitypub/users/#{user.id}" + end +end +``` + +### 4. Configuration & Middleware + +Make sure you have the necessary CORS headers set up, as remote servers will need to access the Webfinger endpoint. + +Additionally, consider caching the Webfinger responses, since the data doesn't change frequently. This will reduce the load on your server. + +### 5. Documentation + +Lastly, document your Webfinger endpoint, so developers from other services know how to discover users on your platform. You might want to link to the official Webfinger specification for further details. + +With these steps, you should have a basic Webfinger implementation that allows other servers to discover users on your platform via their `@user@domain.com` identifier. \ No newline at end of file