ActivityPub in OCaml using jsont/eio/requests

ActivityPub Implementation Plan#

Overview#

The requests library already provides RFC 9421 HTTP Message Signatures via Requests.Signature. This simplifies Phase 1 significantly - we just need to integrate the existing signing.

Phase 1: Integrate HTTP Signatures ✓#

The requests library provides:

  • Signature.config - signing configuration with key, keyid, components
  • Signature.Key - Ed25519, RSA, ECDSA P-256/P-384, HMAC keys
  • Signature.sign - sign request headers
  • Signature.sign_with_digest - sign with Content-Digest (RFC 9530)
  • Signature.verify - verify signatures
  • Signature.Content_digest - body digest computation

1.1 Update Apubt.Signing ✓#

  • Already has key_id and private_key fields
  • Add proper Key.t construction from PEM
  • Configure default signed components for ActivityPub

1.2 Integrate into Http.post ✓#

  • Create signature config from Apubt.Signing
  • Sign requests before sending
  • Add Content-Digest for POST bodies

Phase 2: Activity Delivery ✓#

2.1 Inbox Delivery ✓#

  • Inbox.post - POST signed activity to inbox URI
  • Inbox.post_to_actor - resolve inbox from actor, deliver
  • Inbox.post_to_shared_inbox - batch delivery to shared inbox

2.2 Recipient Resolution ✓#

  • Extract recipients from to/cc/bto/bcc fields
  • Dereference collection URIs to get actor list
  • Handle Public collection (use shared inbox)
  • De-duplicate recipients

Phase 3: Outbox Operations ✓#

3.1 Note Creation ✓#

  • Outbox.create_note - construct Create(Note) activity
  • Outbox.public_note - to: Public, cc: followers
  • Outbox.followers_only_note - to: followers only
  • Outbox.direct_note - to: specific actors
  • Generate unique activity/object IDs

3.2 Interactions ✓#

  • Outbox.like - Like activity
  • Outbox.unlike - Undo(Like)
  • Outbox.announce - boost/reblog
  • Outbox.unannounce - Undo(Announce)

3.3 Modifications ✓#

  • Outbox.delete - Delete with Tombstone
  • Outbox.update_note - Update activity

Phase 4: Follow Protocol ✓#

4.1 Outgoing Follows ✓#

  • Actor.follow - send Follow to target inbox
  • Actor.unfollow - send Undo(Follow)

4.2 Incoming Follows ✓#

  • Actor.accept_follow - send Accept(Follow)
  • Actor.reject_follow - send Reject(Follow)

Phase 5: Proto Properties ✓#

5.1 Actor Properties ✓#

  • also_known_as: Uri.t list option
  • discoverable: bool option
  • suspended: bool option
  • moved_to: Uri.t option
  • featured: Uri.t option
  • featured_tags: Uri.t option

5.2 Object Properties ✓#

  • conversation: Uri.t option (conversation threading)
  • audience: Recipient.t list option
  • location: Link_or_uri.t option
  • preview: Link_or_uri.t option

5.3 Question Activity ✓#

  • one_of: Object_ref.t list option
  • any_of: Object_ref.t list option
  • closed: Datetime.t option

Phase 6: NodeInfo ✓#

  • Fetch /.well-known/nodeinfo
  • Parse nodeinfo links for schema 2.0/2.1
  • Fetch and decode nodeinfo document

Phase 7: CLI Enhancements ✓#

Current commands:

  • apub webfinger - look up account via Webfinger
  • apub actor - fetch an ActivityPub actor
  • apub outbox - fetch an actor's outbox
  • apub post - create and post a note
  • apub follow - follow an actor
  • apub like - like a post
  • apub boost - announce/reblog a post

Phase 8: WebFinger Integration ✓#

Integrated the webfinger library for RFC 7033/7565 compliant discovery:

  • Use Webfinger.query_acct for proper acct URI handling
  • Support for percent-encoding in userparts
  • Added Webfinger.lookup_raw for efficient direct JRD access
  • Added ActivityPub WebFinger spec to spec/ directory

Implementation Order#

Phase 1.1-1.2 (Signing integration) ✓
    ↓
Phase 2 (Delivery) ✓ ──→ Phase 4 (Follow) ✓
    ↓
Phase 3 (Outbox) ✓
    ↓
Phase 7 (CLI) ✓
    ↓
Phase 8 (WebFinger) ✓

Phase 5 (Properties) ✓
Phase 6 (NodeInfo) ✓

Completed#

All phases are now complete. The library provides:

  • Full HTTP signature support (RFC 9421)
  • Activity delivery to inboxes
  • Outbox operations (create, like, boost, delete, update)
  • Follow protocol (follow, unfollow, accept, reject)
  • Question/poll activity support
  • NodeInfo discovery
  • Complete CLI with read and write operations
  • RFC 7033/7565 compliant WebFinger via the webfinger library