activity/pub
Cory Slep 9417306aa3 Outline the needed federating side effects tests. 2019-02-24 13:05:00 +01:00
..
README.md Move `streams` to `streams_old` in preparation for the new vocabulary. 2019-01-29 22:16:19 +01:00
activity.go Finish porting the core of pub. 2019-02-14 21:51:57 +01:00
actor.go Update interface definitions and wrapper improvements. 2019-02-15 21:03:43 +01:00
base_actor.go Update authn and authz functions to have intuitive return values 2019-02-19 20:40:26 +01:00
base_actor_test.go Update authn and authz functions to have intuitive return values 2019-02-19 20:40:26 +01:00
clock.go First pass converting to new pub library. 2019-02-12 00:16:33 +01:00
common_behavior.go Update authn and authz functions to have intuitive return values 2019-02-19 20:40:26 +01:00
database.go Always acquire db lock before calling Owns 2019-02-15 22:04:08 +01:00
delegate_actor.go Update authn and authz functions to have intuitive return values 2019-02-19 20:40:26 +01:00
doc.go First pass converting to new pub library. 2019-02-12 00:16:33 +01:00
federating_protocol.go Increase side effect actor test coverage. 2019-02-20 21:31:11 +01:00
federating_wrapped_callbacks.go Outline the needed federating side effects tests. 2019-02-24 13:05:00 +01:00
federating_wrapped_callbacks_test.go Outline the needed federating side effects tests. 2019-02-24 13:05:00 +01:00
handlers.go Port ActivityStreams http handler function. 2019-02-14 22:28:46 +01:00
mock_clock_test.go Add tests for the base actor. 2019-02-16 20:30:18 +01:00
mock_common_behavior_test.go Some tests for the side_effect_actor.go 2019-02-19 20:33:22 +01:00
mock_database_test.go Some tests for the side_effect_actor.go 2019-02-19 20:33:22 +01:00
mock_delegate_actor_test.go Add tests for the base actor. 2019-02-16 20:30:18 +01:00
mock_federating_protocol_test.go Increase side effect actor test coverage. 2019-02-20 21:31:11 +01:00
mock_social_protocol_test.go Increase side effect actor test coverage. 2019-02-20 21:31:11 +01:00
property_interfaces.go Update interface definitions and wrapper improvements. 2019-02-15 21:03:43 +01:00
pub_test.go Outline the needed federating side effects tests. 2019-02-24 13:05:00 +01:00
side_effect_actor.go More unit tests and bug fixes. 2019-02-23 18:42:40 +01:00
side_effect_actor_test.go More unit tests and bug fixes. 2019-02-23 18:42:40 +01:00
social_protocol.go Increase side effect actor test coverage. 2019-02-20 21:31:11 +01:00
social_wrapped_callbacks.go Generate generic ToType function. 2019-02-15 22:47:59 +01:00
transport.go Update interface definitions and wrapper improvements. 2019-02-15 21:03:43 +01:00
util.go Outline the needed federating side effects tests. 2019-02-24 13:05:00 +01:00
util_test.go Add tests for the base actor. 2019-02-16 20:30:18 +01:00
version.go First pass converting to new pub library. 2019-02-12 00:16:33 +01:00

README.md

pub

Implements both the SocialAPI and FederateAPI in the ActivityPub specification.

Disclaimer

This library is designed with flexibility in mind. The cost of doing so is that writing an ActivityPub application requires a lot of careful considerations that are not trivial. ActivityPub is an Application transport layer that is also tied to a specific data model, making retrofits nontrivial as well.

How To Use

There are two ActivityPub APIs: the SocialAPI between a user and your ActivityPub server, and the FederateAPI between your ActivityPub server and another server peer. This library lets you choose one or both.

Lightning intro to ActivityPub: ActivityPub uses ActivityStreams as data. This lives in go-fed/activity/vocab. ActivityPub has a concept of actors who can send, receive, and read their messages. When sending and receiving messages from a client (such as on their phone) to an ActivityPub server, it is via the SocialAPI. When it is between two ActivityPub servers, it is via the FederateAPI.

Next, there are two kinds of ActivityPub requests to handle:

  1. Requests that GET or POST to stuff owned by an actor like their inbox or outbox.
  2. Requests that GET ActivityStream objects hosted on your server.

The first is the most complex, and requires the creation of a Pubber. It is created depending on which APIs are to be supported:

// Only support SocialAPI
s := pub.NewSocialPubber(...)
// Only support FederateAPI
f := pub.NewFederatingPubber(...)
// Support both APIs
sf := pub.NewPubber(...)

Note that only the creation of the Pubber is affected by the decision of which API to support. Once created, the Pubber should be used in the same manner regardless of the API it is supporting. This allows your application to easily adopt one API first and migrate to both later by simply changing how the Pubber is created.

To use the Pubber, call its methods in the HTTP handlers responsible for an actor's inbox and outbox:

// Given:
//     var myPubber pub.Pubber
var outboxHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
  c := context.Background()
  // Populate c with application specific information
  if handled, err := myPubber.PostOutbox(c, w, r); err != nil {
    // Write to w
  } else if handled {
    return
  }
  if handled, err := myPubber.GetOutbox(c, w, r); err != nil {
    // Write to w
  } else if handled {
    return
  }
  // Handle non-ActivityPub request, such as responding with an HTML
  // representation with correct view permissions.
}
var inboxHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
  c := context.Background()
  // Populate c with application specific information
  if handled, err := myPubber.PostInbox(c, w, r); err != nil {
    // Write to w
  } else if handled {
    return
  }
  if handled, err := myPubber.GetInbox(c, w, r); err != nil {
    // Write to w
  } else if handled {
    return
  }
  // Handle non-ActivityPub request, such as responding with an HTML
  // representation with correct view permissions.
}

Finally, to handle the second kind of request, use the HandlerFunc within HTTP handler functions in a similar way. There are two ways to create HandlerFunc, which depend on decisions we will address later:

asHandler := pub.ServeActivityPubObject(...)
var activityStreamHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
  c := context.Background()
  // Populate c with application specific information
  if handled, err := asHandler(c, w, r); err != nil {
    // Write to w
  } else if handled {
    return
  }
  // Handle non-ActivityPub request, such as responding with an HTML
  // representation with correct view permissions.
}

That's all that's required to support ActivityPub.

How To Create

You may have noticed that using the library is deceptively straightforward. This is because creating the Pubber and HandlerFunc types is not trivial and requires forethought.

There are a lot of interfaces that must be satisfied in order to have a complete working ActivityPub server.

Note that context.Context is passed everywhere possible, to allow your implementation to keep a request-specific context throughout the lifecycle of an ActivityPub request.

Application Interface

Regardless of which of the SocialAPI and FederateAPI chosen, the Application interface contains the set of core methods fundamental to the functionality of this library. It contains a lot of the storage fetching and writing, all of which is keyed by *url.URL. To protect against race conditions, this library will inform whether it is fetching data to read-only or fetching for read-or- write.

Note that under some conditions, ActivityPub verifies the peer's request. It does so using HTTP Signatures. However, this requires knowing the other party's public key, and fetching this remotely is do-able. However, this library assumes this server already has it locally; at this time it is up to implementations to remotely fetch it if needed.

SocialAPI and FederateAPI Interfaces

These interfaces capture additional behaviors required by the SocialAPI and the FederateAPI.

The SocialAPI can additionally provide a mechanism for client authentication and authorization using frameworks like Oauth 2.0. Such frameworks are not natively supported in this library and must be supplied.

Callbacker Interface

One of these is needed per ActivityPub API supported. For example, if both the SocialAPI and FederateAPI are supported, then two of these are needed.

Upon receiving one of these activities from a POST to the inbox or outbox, the correct callbacker will be called to handle either a SocialAPI activity or a FederateAPI activity.

This is where the bulk of implementation-specific logic is expected to reside.

Do note that for some of these activities, default actions will already occur. For example, if receiving an Accept in response to a sent Follow, this library automatically handles adding the correct actor into the correct following collection. This means a lot of the social and federate functionality is provided out of the box.

Deliverer Interface

This is an optional interface. Since this library needs to send HTTP requests, it would be unwise for it to provide no way of allowing implementations to rate limit, persist across downtime, back off, etc. This interface is satisfied by the go-fed/activity/deliverer package which has an implementation that can remember to send requests across downtime.

If an implementation does not care to have this level of control, a synchronous implementation is very straightforward to make.

Other Interfaces

Other interfaces such as Typer and PubObject are meant to limit modification scope or require minimal ActivityStream compatibility to be used by this library. As long as the go-fed/activity/vocab or go-fed/activity/streams_old packages are being used, these interfaces will be natively supported.

Other Considerations

Please see the README for go-fed/activity for the status of the latest official implementation report.

The go-fed.org website has a tutorial and documentation for this library.