pub

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 9, 2020 License: BSD-3-Clause Imports: 17 Imported by: 27

README

pub

Implements the Social and Federating Protocols in the ActivityPub specification.

Reference & Tutorial

The go-fed website contains tutorials and reference materials, in addition to the rest of this README.

How To Use

go get github.com/go-fed/activity

The root of all ActivityPub behavior is the Actor, which requires you to implement a few interfaces:

import (
  "github.com/go-fed/activity/pub"
)

type myActivityPubApp struct { /* ... */ }
type myAppsDatabase struct { /* ... */ }
type myAppsClock struct { /* ... */ }

var (
  // Your app will implement pub.CommonBehavior, and either
  // pub.SocialProtocol, pub.FederatingProtocol, or both.
  myApp = &myActivityPubApp{}
  myCommonBehavior pub.CommonBehavior = myApp
  mySocialProtocol pub.SocialProtocol = myApp
  myFederatingProtocol pub.FederatingProtocol = myApp
  // Your app's database implementation.
  myDatabase pub.Database = &myAppsDatabase{}
  // Your app's clock.
  myClock pub.Clock = &myAppsClock{}
)

// Only support the C2S Social protocol
actor := pub.NewSocialActor(
  myCommonBehavior,
  mySocialProtocol,
  myDatabase,
  myClock)
// OR
//
// Only support S2S Federating protocol
actor = pub.NewFederatingActor(
  myCommonBehavior,
  myFederatingProtocol,
  myDatabase,
  myClock)
// OR
//
// Support both C2S Social and S2S Federating protocol.
actor = pub.NewActor(
  myCommonBehavior,
  mySocialProtocol,
  myFederatingProtocol,
  myDatabase,
  myClock)

Next, hook the Actor into your web server:

// The application's actor
var actor pub.Actor
var outboxHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
  c := context.Background()
  // Populate c with request-specific information
  if handled, err := actor.PostOutbox(c, w, r); err != nil {
    // Write to w
    return
  } else if handled {
    return
  } else if handled, err = actor.GetOutbox(c, w, r); err != nil {
    // Write to w
    return
  } else if handled {
    return
  }
  // else:
  //
  // Handle non-ActivityPub request, such as serving a webpage.
}
var inboxHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
  c := context.Background()
  // Populate c with request-specific information
  if handled, err := actor.PostInbox(c, w, r); err != nil {
    // Write to w
    return
  } else if handled {
    return
  } else if handled, err = actor.GetInbox(c, w, r); err != nil {
    // Write to w
    return
  } else if handled {
    return
  }
  // else:
  //
  // Handle non-ActivityPub request, such as serving a webpage.
}
// Add the handlers to a HTTP server
serveMux := http.NewServeMux()
serveMux.HandleFunc("/actor/outbox", outboxHandler)
serveMux.HandleFunc("/actor/inbox", inboxHandler)
var server http.Server
server.Handler = serveMux

To serve ActivityStreams data:

myHander := pub.NewActivityStreamsHandler(myDatabase, myClock)
var activityStreamsHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
  c := context.Background()
  // Populate c with request-specific information
  if handled, err := myHandler(c, w, r); err != nil {
    // Write to w
    return
  } else if handled {
    return
  }
  // else:
  //
  // Handle non-ActivityPub request, such as serving a webpage.
}
serveMux.HandleFunc("/some/data/like/a/note", activityStreamsHandler)
Dependency Injection

Package pub relies on dependency injection to provide out-of-the-box support for ActivityPub. The interfaces to be satisfied are:

  • CommonBehavior - Behavior needed regardless of which Protocol is used.
  • SocialProtocol - Behavior needed for the Social Protocol.
  • FederatingProtocol - Behavior needed for the Federating Protocol.
  • Database - The data store abstraction, not tied to the database/sql package.
  • Clock - The server's internal clock.
  • Transport - Responsible for the network that serves requests and deliveries of ActivityStreams data. A HttpSigTransport type is provided.

These implementations form the core of an application's behavior without worrying about the particulars and pitfalls of the ActivityPub protocol. Implementing these interfaces gives you greater assurance about being ActivityPub compliant.

Application Logic

The SocialProtocol and FederatingProtocol are responsible for returning callback functions compatible with streams.TypeResolver. They also return SocialWrappedCallbacks and FederatingWrappedCallbacks, which are nothing more than a bundle of default behaviors for types like Create, Update, and so on.

Applications will want to focus on implementing their specific behaviors in the callbacks, and have fine-grained control over customization:

// Implements the FederatingProtocol interface.
//
// This illustration can also be applied for the Social Protocol.
func (m *myAppsFederatingProtocol) Callbacks(c context.Context) (wrapped pub.FederatingWrappedCallbacks, other []interface{}) {
  // The context 'c' has request-specific logic and can be used to apply complex
  // logic building the right behaviors, if desired.
  //
  // 'c' will later be passed through to the callbacks created below.
  wrapped = pub.FederatingWrappedCallbacks{
    Create: func(ctx context.Context, create vocab.ActivityStreamsCreate) error {
      // This function is wrapped by default behavior.
      //
      // More application specific logic can be written here.
      //
      // 'ctx' will have request-specific information from the HTTP handler. It
      // is the same as the 'c' passed to the Callbacks method.
      // 'create' has, at this point, already triggered the recommended
      // ActivityPub side effect behavior. The application can process it
      // further as needed.
      return nil
    },
  }
  // The 'other' must contain functions that satisfy the signature pattern
  // required by streams.JSONResolver.
  //
  // If they are not, at runtime errors will be returned to indicate this.
  other = []interface{}{
    // The FederatingWrappedCallbacks has default behavior for an "Update" type,
    // but since we are providing this behavior in "other" and not in the
    // FederatingWrappedCallbacks.Update member, we will entirely replace the
    // default behavior provided by go-fed. Be careful that this still
    // implements ActivityPub properly.
    func(ctx context.Context, update vocab.ActivityStreamsUpdate) error {
      // This function is NOT wrapped by default behavior.
      //
      // Application specific logic can be written here.
      //
      // 'ctx' will have request-specific information from the HTTP handler. It
      // is the same as the 'c' passed to the Callbacks method.
      // 'update' will NOT trigger the recommended ActivityPub side effect
      // behavior. The application should do so in addition to any other custom
      // side effects required.
      return nil
    },
    // The "Listen" type has no default suggested behavior in ActivityPub, so
    // this just makes this application able to handle "Listen" activities.
    func(ctx context.Context, listen vocab.ActivityStreamsListen) error {
      // This function is NOT wrapped by default behavior. There's not a
      // FederatingWrappedCallbacks.Listen member to wrap.
      //
      // Application specific logic can be written here.
      //
      // 'ctx' will have request-specific information from the HTTP handler. It
      // is the same as the 'c' passed to the Callbacks method.
      // 'listen' can be processed with side effects as the application needs.
      return nil
    },
  }
  return
}

The pub package supports applications that grow into more custom solutions by overriding the default behaviors as needed.

ActivityStreams Extensions: Future-Proofing An Application

Package pub relies on the streams.TypeResolver and streams.JSONResolver code generated types. As new ActivityStreams extensions are developed and their code is generated, pub will automatically pick up support for these extensions.

The steps to rapidly implement a new extension in a pub application are:

  1. Generate an OWL definition of the ActivityStreams extension. This definition could be the same one defining the vocabulary at the @context IRI.
  2. Run astool to autogenerate the golang types in the streams package.
  3. Implement the application's callbacks in the FederatingProtocol.Callbacks or SocialProtocol.Callbacks for the new behaviors needed.
  4. Build the application, which builds pub, with the newly generated streams code. No code changes in pub are required.

Whether an author of an ActivityStreams extension or an application developer, these quick steps should reduce the barrier to adopion in a statically-typed environment.

DelegateActor

For those that need a near-complete custom ActivityPub solution, or want to have that possibility in the future after adopting go-fed, the DelegateActor interface can be used to obtain an Actor:

// Use custom ActivityPub implementation
actor = pub.NewCustomActor(
  myDelegateActor,
  isSocialProtocolEnabled,
  isFederatedProtocolEnabled,
  myAppsClock)

It does not guarantee that an implementation adheres to the ActivityPub specification. It acts as a stepping stone for applications that want to build up to a fully custom solution and not be locked into the pub package implementation.

Documentation

Overview

Package pub implements the ActivityPub protocol.

Note that every time the ActivityStreams types are changed (added, removed) due to code generation, the internal function toASType needs to be modified to know about these types.

Note that every version change should also include a change in the version.go file.

Index

Constants

View Source
const (
	// PublicActivityPubIRI is the IRI that indicates an Activity is meant
	// to be visible for general public consumption.
	PublicActivityPubIRI = "https://www.w3.org/ns/activitystreams#Public"
)

Variables

View Source
var (
	// ErrObjectRequired indicates the activity needs its object property
	// set. Can be returned by DelegateActor's PostInbox or PostOutbox so a
	// Bad Request response is set.
	ErrObjectRequired = errors.New("object property required on the provided activity")
	// ErrTargetRequired indicates the activity needs its target property
	// set. Can be returned by DelegateActor's PostInbox or PostOutbox so a
	// Bad Request response is set.
	ErrTargetRequired = errors.New("target property required on the provided activity")
)

Functions

func GetId added in v1.0.0

func GetId(t vocab.Type) (*url.URL, error)

GetId will attempt to find the 'id' property or, if it happens to be a Link or derived from Link type, the 'href' property instead.

Returns an error if the id is not set and either the 'href' property is not valid on this type, or it is also not set.

func IsPublic added in v1.0.0

func IsPublic(s string) bool

IsPublic determines if an IRI string is the Public collection as defined in the spec, including JSON-LD compliant collections.

func ToId added in v1.0.0

func ToId(i IdProperty) (*url.URL, error)

ToId returns an IdProperty's id.

Types

type Activity added in v1.0.0

type Activity interface {
	// Activity is also a vocab.Type
	vocab.Type
	// GetActivityStreamsActor returns the "actor" property if it exists, and
	// nil otherwise.
	GetActivityStreamsActor() vocab.ActivityStreamsActorProperty
	// GetActivityStreamsAudience returns the "audience" property if it
	// exists, and nil otherwise.
	GetActivityStreamsAudience() vocab.ActivityStreamsAudienceProperty
	// GetActivityStreamsBcc returns the "bcc" property if it exists, and nil
	// otherwise.
	GetActivityStreamsBcc() vocab.ActivityStreamsBccProperty
	// GetActivityStreamsBto returns the "bto" property if it exists, and nil
	// otherwise.
	GetActivityStreamsBto() vocab.ActivityStreamsBtoProperty
	// GetActivityStreamsCc returns the "cc" property if it exists, and nil
	// otherwise.
	GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
	// GetActivityStreamsTo returns the "to" property if it exists, and nil
	// otherwise.
	GetActivityStreamsTo() vocab.ActivityStreamsToProperty
	// GetActivityStreamsAttributedTo returns the "attributedTo" property if
	// it exists, and nil otherwise.
	GetActivityStreamsAttributedTo() vocab.ActivityStreamsAttributedToProperty
	// GetActivityStreamsObject returns the "object" property if it exists,
	// and nil otherwise.
	GetActivityStreamsObject() vocab.ActivityStreamsObjectProperty
	// SetActivityStreamsActor sets the "actor" property.
	SetActivityStreamsActor(i vocab.ActivityStreamsActorProperty)
	// SetActivityStreamsObject sets the "object" property.
	SetActivityStreamsObject(i vocab.ActivityStreamsObjectProperty)
	// SetActivityStreamsTo sets the "to" property.
	SetActivityStreamsTo(i vocab.ActivityStreamsToProperty)
	// SetActivityStreamsBto sets the "bto" property.
	SetActivityStreamsBto(i vocab.ActivityStreamsBtoProperty)
	// SetActivityStreamsBcc sets the "bcc" property.
	SetActivityStreamsBcc(i vocab.ActivityStreamsBccProperty)
	// SetActivityStreamsAttributedTo sets the "attributedTo" property.
	SetActivityStreamsAttributedTo(i vocab.ActivityStreamsAttributedToProperty)
}

Activity represents any ActivityStreams Activity type.

The Activity types provided in the streams package implement this.

type Actor added in v1.0.0

type Actor interface {
	// PostInbox returns true if the request was handled as an ActivityPub
	// POST to an actor's inbox. If false, the request was not an
	// ActivityPub request and may still be handled by the caller in
	// another way, such as serving a web page.
	//
	// If the error is nil, then the ResponseWriter's headers and response
	// has already been written. If a non-nil error is returned, then no
	// response has been written.
	//
	// If the Actor was constructed with the Federated Protocol enabled,
	// side effects will occur.
	//
	// If the Federated Protocol is not enabled, writes the
	// http.StatusMethodNotAllowed status code in the response. No side
	// effects occur.
	PostInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error)
	// GetInbox returns true if the request was handled as an ActivityPub
	// GET to an actor's inbox. If false, the request was not an ActivityPub
	// request and may still be handled by the caller in another way, such
	// as serving a web page.
	//
	// If the error is nil, then the ResponseWriter's headers and response
	// has already been written. If a non-nil error is returned, then no
	// response has been written.
	//
	// If the request is an ActivityPub request, the Actor will defer to the
	// application to determine the correct authorization of the request and
	// the resulting OrderedCollection to respond with. The Actor handles
	// serializing this OrderedCollection and responding with the correct
	// headers and http.StatusOK.
	GetInbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error)
	// PostOutbox returns true if the request was handled as an ActivityPub
	// POST to an actor's outbox. If false, the request was not an
	// ActivityPub request and may still be handled by the caller in another
	// way, such as serving a web page.
	//
	// If the error is nil, then the ResponseWriter's headers and response
	// has already been written. If a non-nil error is returned, then no
	// response has been written.
	//
	// If the Actor was constructed with the Social Protocol enabled, side
	// effects will occur.
	//
	// If the Social Protocol is not enabled, writes the
	// http.StatusMethodNotAllowed status code in the response. No side
	// effects occur.
	//
	// If the Social and Federated Protocol are both enabled, it will handle
	// the side effects of receiving an ActivityStream Activity, and then
	// federate the Activity to peers.
	PostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error)
	// GetOutbox returns true if the request was handled as an ActivityPub
	// GET to an actor's outbox. If false, the request was not an
	// ActivityPub request.
	//
	// If the error is nil, then the ResponseWriter's headers and response
	// has already been written. If a non-nil error is returned, then no
	// response has been written.
	//
	// If the request is an ActivityPub request, the Actor will defer to the
	// application to determine the correct authorization of the request and
	// the resulting OrderedCollection to respond with. The Actor handles
	// serializing this OrderedCollection and responding with the correct
	// headers and http.StatusOK.
	GetOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (bool, error)
}

Actor represents ActivityPub's actor concept. It conceptually has an inbox and outbox that receives either a POST or GET request, which triggers side effects in the federating application.

An Actor within an application may federate server-to-server (Federation Protocol), client-to-server (Social API), or both. The Actor represents the server in either use case.

An actor can be created by calling NewSocialActor (only the Social Protocol is supported), NewFederatingActor (only the Federating Protocol is supported), NewActor (both are supported), or NewCustomActor (neither are).

Not all Actors have the same behaviors depending on the constructor used to create them. Refer to the constructor's documentation to determine the exact behavior of the Actor on an application.

The behaviors documented here are common to all Actors returned by any constructor.

func NewSocialActor added in v1.0.0

func NewSocialActor(c CommonBehavior,
	c2s SocialProtocol,
	db Database,
	clock Clock) Actor

NewSocialActor builds a new Actor concept that handles only the Social Protocol part of ActivityPub.

This Actor can be created once in an application and reused to handle multiple requests concurrently and for different endpoints.

It leverages as much of go-fed as possible to ensure the implementation is compliant with the ActivityPub specification, while providing enough freedom to be productive without shooting one's self in the foot.

Do not try to use NewSocialActor and NewFederatingActor together to cover both the Social and Federating parts of the protocol. Instead, use NewActor.

type Clock

type Clock interface {
	// Now returns the current time.
	Now() time.Time
}

Clock determines the time.

type CommonBehavior added in v1.0.0

type CommonBehavior interface {
	// AuthenticateGetInbox delegates the authentication of a GET to an
	// inbox.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled.
	//
	// If an error is returned, it is passed back to the caller of
	// GetInbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authenticated' is ignored.
	//
	// If no error is returned, but authentication or authorization fails,
	// then authenticated must be false and error nil. It is expected that
	// the implementation handles writing to the ResponseWriter in this
	// case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authenticated must be true and error nil. The request will continue
	// to be processed.
	AuthenticateGetInbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error)
	// AuthenticateGetOutbox delegates the authentication of a GET to an
	// outbox.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled.
	//
	// If an error is returned, it is passed back to the caller of
	// GetOutbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authenticated' is ignored.
	//
	// If no error is returned, but authentication or authorization fails,
	// then authenticated must be false and error nil. It is expected that
	// the implementation handles writing to the ResponseWriter in this
	// case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authenticated must be true and error nil. The request will continue
	// to be processed.
	AuthenticateGetOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error)
	// GetOutbox returns the OrderedCollection inbox of the actor for this
	// context. It is up to the implementation to provide the correct
	// collection for the kind of authorization given in the request.
	//
	// AuthenticateGetOutbox will be called prior to this.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled.
	GetOutbox(c context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error)
	// NewTransport returns a new Transport on behalf of a specific actor.
	//
	// The actorBoxIRI will be either the inbox or outbox of an actor who is
	// attempting to do the dereferencing or delivery. Any authentication
	// scheme applied on the request must be based on this actor. The
	// request must contain some sort of credential of the user, such as a
	// HTTP Signature.
	//
	// The gofedAgent passed in should be used by the Transport
	// implementation in the User-Agent, as well as the application-specific
	// user agent string. The gofedAgent will indicate this library's use as
	// well as the library's version number.
	//
	// Any server-wide rate-limiting that needs to occur should happen in a
	// Transport implementation. This factory function allows this to be
	// created, so peer servers are not DOS'd.
	//
	// Any retry logic should also be handled by the Transport
	// implementation.
	//
	// Note that the library will not maintain a long-lived pointer to the
	// returned Transport so that any private credentials are able to be
	// garbage collected.
	NewTransport(c context.Context, actorBoxIRI *url.URL, gofedAgent string) (t Transport, err error)
}

Common contains functions required for both the Social API and Federating Protocol.

It is passed to the library as a dependency injection from the client application.

type Database added in v1.0.0

type Database interface {
	// Lock takes a lock for the object at the specified id. If an error
	// is returned, the lock must not have been taken.
	//
	// The lock must be able to succeed for an id that does not exist in
	// the database. This means acquiring the lock does not guarantee the
	// entry exists in the database.
	//
	// Locks are encouraged to be lightweight and in the Go layer, as some
	// processes require tight loops acquiring and releasing locks.
	//
	// Used to ensure race conditions in multiple requests do not occur.
	Lock(c context.Context, id *url.URL) error
	// Unlock makes the lock for the object at the specified id available.
	// If an error is returned, the lock must have still been freed.
	//
	// Used to ensure race conditions in multiple requests do not occur.
	Unlock(c context.Context, id *url.URL) error
	// InboxContains returns true if the OrderedCollection at 'inbox'
	// contains the specified 'id'.
	//
	// The library makes this call only after acquiring a lock first.
	InboxContains(c context.Context, inbox, id *url.URL) (contains bool, err error)
	// GetInbox returns the first ordered collection page of the outbox at
	// the specified IRI, for prepending new items.
	//
	// The library makes this call only after acquiring a lock first.
	GetInbox(c context.Context, inboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error)
	// SetInbox saves the inbox value given from GetInbox, with new items
	// prepended. Note that the new items must not be added as independent
	// database entries. Separate calls to Create will do that.
	//
	// The library makes this call only after acquiring a lock first.
	SetInbox(c context.Context, inbox vocab.ActivityStreamsOrderedCollectionPage) error
	// Owns returns true if the database has an entry for the IRI and it
	// exists in the database.
	//
	// The library makes this call only after acquiring a lock first.
	Owns(c context.Context, id *url.URL) (owns bool, err error)
	// ActorForOutbox fetches the actor's IRI for the given outbox IRI.
	//
	// The library makes this call only after acquiring a lock first.
	ActorForOutbox(c context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error)
	// ActorForInbox fetches the actor's IRI for the given outbox IRI.
	//
	// The library makes this call only after acquiring a lock first.
	ActorForInbox(c context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error)
	// OutboxForInbox fetches the corresponding actor's outbox IRI for the
	// actor's inbox IRI.
	//
	// The library makes this call only after acquiring a lock first.
	OutboxForInbox(c context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error)
	// Exists returns true if the database has an entry for the specified
	// id. It may not be owned by this application instance.
	//
	// The library makes this call only after acquiring a lock first.
	Exists(c context.Context, id *url.URL) (exists bool, err error)
	// Get returns the database entry for the specified id.
	//
	// The library makes this call only after acquiring a lock first.
	Get(c context.Context, id *url.URL) (value vocab.Type, err error)
	// Create adds a new entry to the database which must be able to be
	// keyed by its id.
	//
	// Note that Activity values received from federated peers may also be
	// created in the database this way if the Federating Protocol is
	// enabled. The client may freely decide to store only the id instead of
	// the entire value.
	//
	// The library makes this call only after acquiring a lock first.
	//
	// Under certain conditions and network activities, Create may be called
	// multiple times for the same ActivityStreams object.
	Create(c context.Context, asType vocab.Type) error
	// Update sets an existing entry to the database based on the value's
	// id.
	//
	// Note that Activity values received from federated peers may also be
	// updated in the database this way if the Federating Protocol is
	// enabled. The client may freely decide to store only the id instead of
	// the entire value.
	//
	// The library makes this call only after acquiring a lock first.
	Update(c context.Context, asType vocab.Type) error
	// Delete removes the entry with the given id.
	//
	// Delete is only called for federated objects. Deletes from the Social
	// Protocol instead call Update to create a Tombstone.
	//
	// The library makes this call only after acquiring a lock first.
	Delete(c context.Context, id *url.URL) error
	// GetOutbox returns the first ordered collection page of the outbox
	// at the specified IRI, for prepending new items.
	//
	// The library makes this call only after acquiring a lock first.
	GetOutbox(c context.Context, outboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error)
	// SetOutbox saves the outbox value given from GetOutbox, with new items
	// prepended. Note that the new items must not be added as independent
	// database entries. Separate calls to Create will do that.
	//
	// The library makes this call only after acquiring a lock first.
	SetOutbox(c context.Context, outbox vocab.ActivityStreamsOrderedCollectionPage) error
	// NewID creates a new IRI id for the provided activity or object. The
	// implementation does not need to set the 'id' property and simply
	// needs to determine the value.
	//
	// The go-fed library will handle setting the 'id' property on the
	// activity or object provided with the value returned.
	NewID(c context.Context, t vocab.Type) (id *url.URL, err error)
	// Followers obtains the Followers Collection for an actor with the
	// given id.
	//
	// If modified, the library will then call Update.
	//
	// The library makes this call only after acquiring a lock first.
	Followers(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error)
	// Following obtains the Following Collection for an actor with the
	// given id.
	//
	// If modified, the library will then call Update.
	//
	// The library makes this call only after acquiring a lock first.
	Following(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error)
	// Liked obtains the Liked Collection for an actor with the
	// given id.
	//
	// If modified, the library will then call Update.
	//
	// The library makes this call only after acquiring a lock first.
	Liked(c context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error)
}

type DelegateActor added in v1.0.0

type DelegateActor interface {
	// Hook callback after parsing the request body for a federated request
	// to the Actor's inbox.
	//
	// Can be used to set contextual information based on the Activity
	// received.
	//
	// Only called if the Federated Protocol is enabled.
	//
	// Warning: Neither authentication nor authorization has taken place at
	// this time. Doing anything beyond setting contextual information is
	// strongly discouraged.
	//
	// If an error is returned, it is passed back to the caller of
	// PostInbox. In this case, the DelegateActor implementation must not
	// write a response to the ResponseWriter as is expected that the caller
	// to PostInbox will do so when handling the error.
	PostInboxRequestBodyHook(c context.Context, r *http.Request, activity Activity) (context.Context, error)
	// Hook callback after parsing the request body for a client request
	// to the Actor's outbox.
	//
	// Can be used to set contextual information based on the
	// ActivityStreams object received.
	//
	// Only called if the Social API is enabled.
	//
	// Warning: Neither authentication nor authorization has taken place at
	// this time. Doing anything beyond setting contextual information is
	// strongly discouraged.
	//
	// If an error is returned, it is passed back to the caller of
	// PostOutbox. In this case, the DelegateActor implementation must not
	// write a response to the ResponseWriter as is expected that the caller
	// to PostOutbox will do so when handling the error.
	PostOutboxRequestBodyHook(c context.Context, r *http.Request, data vocab.Type) (context.Context, error)
	// AuthenticatePostInbox delegates the authentication of a POST to an
	// inbox.
	//
	// Only called if the Federated Protocol is enabled.
	//
	// If an error is returned, it is passed back to the caller of
	// PostInbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authenticated' is ignored.
	//
	// If no error is returned, but authentication or authorization fails,
	// then authenticated must be false and error nil. It is expected that
	// the implementation handles writing to the ResponseWriter in this
	// case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authenticated must be true and error nil. The request will continue
	// to be processed.
	AuthenticatePostInbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error)
	// AuthenticateGetInbox delegates the authentication of a GET to an
	// inbox.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled.
	//
	// If an error is returned, it is passed back to the caller of
	// GetInbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authenticated' is ignored.
	//
	// If no error is returned, but authentication or authorization fails,
	// then authenticated must be false and error nil. It is expected that
	// the implementation handles writing to the ResponseWriter in this
	// case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authenticated must be true and error nil. The request will continue
	// to be processed.
	AuthenticateGetInbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error)
	// AuthorizePostInbox delegates the authorization of an activity that
	// has been sent by POST to an inbox.
	//
	// Only called if the Federated Protocol is enabled.
	//
	// If an error is returned, it is passed back to the caller of
	// PostInbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authorized' is ignored.
	//
	// If no error is returned, but authorization fails, then authorized
	// must be false and error nil. It is expected that the implementation
	// handles writing to the ResponseWriter in this case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authorized must be true and error nil. The request will continue
	// to be processed.
	AuthorizePostInbox(c context.Context, w http.ResponseWriter, activity Activity) (authorized bool, err error)
	// PostInbox delegates the side effects of adding to the inbox and
	// determining if it is a request that should be blocked.
	//
	// Only called if the Federated Protocol is enabled.
	//
	// As a side effect, PostInbox sets the federated data in the inbox, but
	// not on its own in the database, as InboxForwarding (which is called
	// later) must decide whether it has seen this activity before in order
	// to determine whether to do the forwarding algorithm.
	//
	// If the error is ErrObjectRequired or ErrTargetRequired, then a Bad
	// Request status is sent in the response.
	PostInbox(c context.Context, inboxIRI *url.URL, activity Activity) error
	// InboxForwarding delegates inbox forwarding logic when a POST request
	// is received in the Actor's inbox.
	//
	// Only called if the Federated Protocol is enabled.
	//
	// The delegate is responsible for determining whether to do the inbox
	// forwarding, as well as actually conducting it if it determines it
	// needs to.
	//
	// As a side effect, InboxForwarding must set the federated data in the
	// database, independently of the inbox, however it sees fit in order to
	// determine whether it has seen the activity before.
	//
	// The provided url is the inbox of the recipient of the Activity. The
	// Activity is examined for the information about who to inbox forward
	// to.
	//
	// If an error is returned, it is returned to the caller of PostInbox.
	InboxForwarding(c context.Context, inboxIRI *url.URL, activity Activity) error
	// PostOutbox delegates the logic for side effects and adding to the
	// outbox.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled. In the case of the Social API being enabled, side
	// effects of the Activity must occur.
	//
	// The delegate is responsible for adding the activity to the database's
	// general storage for independent retrieval, and not just within the
	// actor's outbox.
	//
	// If the error is ErrObjectRequired or ErrTargetRequired, then a Bad
	// Request status is sent in the response.
	//
	// Note that 'rawJSON' is an unfortunate consequence where an 'Update'
	// Activity is the only one that explicitly cares about 'null' values in
	// JSON. Since go-fed does not differentiate between 'null' values and
	// values that are simply not present, the 'rawJSON' map is ONLY needed
	// for this narrow and specific use case.
	PostOutbox(c context.Context, a Activity, outboxIRI *url.URL, rawJSON map[string]interface{}) (deliverable bool, e error)
	// AddNewIDs sets new URL ids on the activity. It also does so for all
	// 'object' properties if the Activity is a Create type.
	//
	// Only called if the Social API is enabled.
	//
	// If an error is returned, it is returned to the caller of PostOutbox.
	AddNewIDs(c context.Context, a Activity) error
	// Deliver sends a federated message. Called only if federation is
	// enabled.
	//
	// Called if the Federated Protocol is enabled.
	//
	// The provided url is the outbox of the sender. The Activity contains
	// the information about the intended recipients.
	//
	// If an error is returned, it is returned to the caller of PostOutbox.
	Deliver(c context.Context, outbox *url.URL, activity Activity) error
	// AuthenticatePostOutbox delegates the authentication and authorization
	// of a POST to an outbox.
	//
	// Only called if the Social API is enabled.
	//
	// If an error is returned, it is passed back to the caller of
	// PostOutbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authenticated' is ignored.
	//
	// If no error is returned, but authentication or authorization fails,
	// then authenticated must be false and error nil. It is expected that
	// the implementation handles writing to the ResponseWriter in this
	// case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authenticated must be true and error nil. The request will continue
	// to be processed.
	AuthenticatePostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error)
	// AuthenticateGetOutbox delegates the authentication of a GET to an
	// outbox.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled.
	//
	// If an error is returned, it is passed back to the caller of
	// GetOutbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authenticated' is ignored.
	//
	// If no error is returned, but authentication or authorization fails,
	// then authenticated must be false and error nil. It is expected that
	// the implementation handles writing to the ResponseWriter in this
	// case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authenticated must be true and error nil. The request will continue
	// to be processed.
	AuthenticateGetOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error)
	// WrapInCreate wraps the provided object in a Create ActivityStreams
	// activity. The provided URL is the actor's outbox endpoint.
	//
	// Only called if the Social API is enabled.
	WrapInCreate(c context.Context, value vocab.Type, outboxIRI *url.URL) (vocab.ActivityStreamsCreate, error)
	// GetOutbox returns the OrderedCollection inbox of the actor for this
	// context. It is up to the implementation to provide the correct
	// collection for the kind of authorization given in the request.
	//
	// AuthenticateGetOutbox will be called prior to this.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled.
	GetOutbox(c context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error)
	// GetInbox returns the OrderedCollection inbox of the actor for this
	// context. It is up to the implementation to provide the correct
	// collection for the kind of authorization given in the request.
	//
	// AuthenticateGetInbox will be called prior to this.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled.
	GetInbox(c context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error)
}

DelegateActor contains the detailed interface an application must satisfy in order to implement the ActivityPub specification.

Note that an implementation of this interface is implicitly provided in the calls to NewActor, NewSocialActor, and NewFederatingActor.

Implementing the DelegateActor requires familiarity with the ActivityPub specification because it does not a strong enough abstraction for the client application to ignore the ActivityPub spec. It is very possible to implement this interface and build a foot-gun that trashes the fediverse without being ActivityPub compliant. Please use with due consideration.

Alternatively, build an application that uses the parts of the pub library that do not require implementing a DelegateActor so that the ActivityPub implementation is completely provided out of the box.

type FederatingActor added in v1.0.0

type FederatingActor interface {
	Actor
	// Send a federated activity.
	//
	// The provided url must be the outbox of the sender. All processing of
	// the activity occurs similarly to the C2S flow:
	//   - If t is not an Activity, it is wrapped in a Create activity.
	//   - A new ID is generated for the activity.
	//   - The activity is added to the specified outbox.
	//   - The activity is prepared and delivered to recipients.
	//
	// Note that this function will only behave as expected if the
	// implementation has been constructed to support federation. This
	// method will guaranteed work for non-custom Actors. For custom actors,
	// care should be used to not call this method if only C2S is supported.
	Send(c context.Context, outbox *url.URL, t vocab.Type) (Activity, error)
}

FederatingActor is an Actor that allows programmatically delivering an Activity to a federating peer.

func NewActor added in v1.0.0

NewActor builds a new Actor concept that handles both the Social and Federating Protocol parts of ActivityPub.

This Actor can be created once in an application and reused to handle multiple requests concurrently and for different endpoints.

It leverages as much of go-fed as possible to ensure the implementation is compliant with the ActivityPub specification, while providing enough freedom to be productive without shooting one's self in the foot.

func NewCustomActor added in v1.0.0

func NewCustomActor(delegate DelegateActor,
	enableSocialProtocol, enableFederatedProtocol bool,
	clock Clock) FederatingActor

NewCustomActor allows clients to create a custom ActivityPub implementation for the Social Protocol, Federating Protocol, or both.

It still uses the library as a high-level scaffold, which has the benefit of allowing applications to grow into a custom ActivityPub solution without having to refactor the code that passes HTTP requests into the Actor.

It is possible to create a DelegateActor that is not ActivityPub compliant. Use with due care.

func NewFederatingActor added in v1.0.0

func NewFederatingActor(c CommonBehavior,
	s2s FederatingProtocol,
	db Database,
	clock Clock) FederatingActor

NewFederatingActor builds a new Actor concept that handles only the Federating Protocol part of ActivityPub.

This Actor can be created once in an application and reused to handle multiple requests concurrently and for different endpoints.

It leverages as much of go-fed as possible to ensure the implementation is compliant with the ActivityPub specification, while providing enough freedom to be productive without shooting one's self in the foot.

Do not try to use NewSocialActor and NewFederatingActor together to cover both the Social and Federating parts of the protocol. Instead, use NewActor.

type FederatingProtocol added in v1.0.0

type FederatingProtocol interface {
	// Hook callback after parsing the request body for a federated request
	// to the Actor's inbox.
	//
	// Can be used to set contextual information based on the Activity
	// received.
	//
	// Only called if the Federated Protocol is enabled.
	//
	// Warning: Neither authentication nor authorization has taken place at
	// this time. Doing anything beyond setting contextual information is
	// strongly discouraged.
	//
	// If an error is returned, it is passed back to the caller of
	// PostInbox. In this case, the DelegateActor implementation must not
	// write a response to the ResponseWriter as is expected that the caller
	// to PostInbox will do so when handling the error.
	PostInboxRequestBodyHook(c context.Context, r *http.Request, activity Activity) (context.Context, error)
	// AuthenticatePostInbox delegates the authentication of a POST to an
	// inbox.
	//
	// If an error is returned, it is passed back to the caller of
	// PostInbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authenticated' is ignored.
	//
	// If no error is returned, but authentication or authorization fails,
	// then authenticated must be false and error nil. It is expected that
	// the implementation handles writing to the ResponseWriter in this
	// case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authenticated must be true and error nil. The request will continue
	// to be processed.
	AuthenticatePostInbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error)
	// Blocked should determine whether to permit a set of actors given by
	// their ids are able to interact with this particular end user due to
	// being blocked or other application-specific logic.
	//
	// If an error is returned, it is passed back to the caller of
	// PostInbox.
	//
	// If no error is returned, but authentication or authorization fails,
	// then blocked must be true and error nil. An http.StatusForbidden
	// will be written in the wresponse.
	//
	// Finally, if the authentication and authorization succeeds, then
	// blocked must be false and error nil. The request will continue
	// to be processed.
	Blocked(c context.Context, actorIRIs []*url.URL) (blocked bool, err error)
	// FederatingCallbacks returns the application logic that handles
	// ActivityStreams received from federating peers.
	//
	// Note that certain types of callbacks will be 'wrapped' with default
	// behaviors supported natively by the library. Other callbacks
	// compatible with streams.TypeResolver can be specified by 'other'.
	//
	// For example, setting the 'Create' field in the
	// FederatingWrappedCallbacks lets an application dependency inject
	// additional behaviors they want to take place, including the default
	// behavior supplied by this library. This is guaranteed to be compliant
	// with the ActivityPub Social protocol.
	//
	// To override the default behavior, instead supply the function in
	// 'other', which does not guarantee the application will be compliant
	// with the ActivityPub Social Protocol.
	//
	// Applications are not expected to handle every single ActivityStreams
	// type and extension. The unhandled ones are passed to DefaultCallback.
	FederatingCallbacks(c context.Context) (wrapped FederatingWrappedCallbacks, other []interface{}, err error)
	// DefaultCallback is called for types that go-fed can deserialize but
	// are not handled by the application's callbacks returned in the
	// Callbacks method.
	//
	// Applications are not expected to handle every single ActivityStreams
	// type and extension, so the unhandled ones are passed to
	// DefaultCallback.
	DefaultCallback(c context.Context, activity Activity) error
	// MaxInboxForwardingRecursionDepth determines how deep to search within
	// an activity to determine if inbox forwarding needs to occur.
	//
	// Zero or negative numbers indicate infinite recursion.
	MaxInboxForwardingRecursionDepth(c context.Context) int
	// MaxDeliveryRecursionDepth determines how deep to search within
	// collections owned by peers when they are targeted to receive a
	// delivery.
	//
	// Zero or negative numbers indicate infinite recursion.
	MaxDeliveryRecursionDepth(c context.Context) int
	// FilterForwarding allows the implementation to apply business logic
	// such as blocks, spam filtering, and so on to a list of potential
	// Collections and OrderedCollections of recipients when inbox
	// forwarding has been triggered.
	//
	// The activity is provided as a reference for more intelligent
	// logic to be used, but the implementation must not modify it.
	FilterForwarding(c context.Context, potentialRecipients []*url.URL, a Activity) (filteredRecipients []*url.URL, err error)
	// GetInbox returns the OrderedCollection inbox of the actor for this
	// context. It is up to the implementation to provide the correct
	// collection for the kind of authorization given in the request.
	//
	// AuthenticateGetInbox will be called prior to this.
	//
	// Always called, regardless whether the Federated Protocol or Social
	// API is enabled.
	GetInbox(c context.Context, r *http.Request) (vocab.ActivityStreamsOrderedCollectionPage, error)
}

FederatingProtocol contains behaviors an application needs to satisfy for the full ActivityPub S2S implementation to be supported by this library.

It is only required if the client application wants to support the server-to- server, or federating, protocol.

It is passed to the library as a dependency injection from the client application.

type FederatingWrappedCallbacks added in v1.0.0

type FederatingWrappedCallbacks struct {
	// Create handles additional side effects for the Create ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping callback for the Federating Protocol ensures the
	// 'object' property is created in the database.
	//
	// Create calls Create for each object in the federated Activity.
	Create func(context.Context, vocab.ActivityStreamsCreate) error
	// Update handles additional side effects for the Update ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping callback for the Federating Protocol ensures the
	// 'object' property is updated in the database.
	//
	// Update calls Update on the federated entry from the database, with a
	// new value.
	Update func(context.Context, vocab.ActivityStreamsUpdate) error
	// Delete handles additional side effects for the Delete ActivityStreams
	// type, specific to the application using go-fed.
	//
	// Delete removes the federated entry from the database.
	Delete func(context.Context, vocab.ActivityStreamsDelete) error
	// Follow handles additional side effects for the Follow ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping function can have one of several default behaviors,
	// depending on the value of the OnFollow setting.
	Follow func(context.Context, vocab.ActivityStreamsFollow) error
	// OnFollow determines what action to take for this particular callback
	// if a Follow Activity is handled.
	OnFollow OnFollowBehavior
	// Accept handles additional side effects for the Accept ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping function determines if this 'Accept' is in response to a
	// 'Follow'. If so, then the 'actor' is added to the original 'actor's
	// 'following' collection.
	//
	// Otherwise, no side effects are done by go-fed.
	Accept func(context.Context, vocab.ActivityStreamsAccept) error
	// Reject handles additional side effects for the Reject ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping function has no default side effects. However, if this
	// 'Reject' is in response to a 'Follow' then the client MUST NOT go
	// forward with adding the 'actor' to the original 'actor's 'following'
	// collection by the client application.
	Reject func(context.Context, vocab.ActivityStreamsReject) error
	// Add handles additional side effects for the Add ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping function will add the 'object' IRIs to a specific
	// 'target' collection if the 'target' collection(s) live on this
	// server.
	Add func(context.Context, vocab.ActivityStreamsAdd) error
	// Remove handles additional side effects for the Remove ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping function will remove all 'object' IRIs from a specific
	// 'target' collection if the 'target' collection(s) live on this
	// server.
	Remove func(context.Context, vocab.ActivityStreamsRemove) error
	// Like handles additional side effects for the Like ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping function will add the activity to the "likes" collection
	// on all 'object' targets owned by this server.
	Like func(context.Context, vocab.ActivityStreamsLike) error
	// Announce handles additional side effects for the Announce
	// ActivityStreams type, specific to the application using go-fed.
	//
	// The wrapping function will add the activity to the "shares"
	// collection on all 'object' targets owned by this server.
	Announce func(context.Context, vocab.ActivityStreamsAnnounce) error
	// Undo handles additional side effects for the Undo ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping function ensures the 'actor' on the 'Undo'
	// is be the same as the 'actor' on all Activities being undone.
	// It enforces that the actors on the Undo must correspond to all of the
	// 'object' actors in some manner.
	//
	// It is expected that the application will implement the proper
	// reversal of activities that are being undone.
	Undo func(context.Context, vocab.ActivityStreamsUndo) error
	// Block handles additional side effects for the Block ActivityStreams
	// type, specific to the application using go-fed.
	//
	// The wrapping function provides no default side effects. It simply
	// calls the wrapped function. However, note that Blocks should not be
	// received from a federated peer, as delivering Blocks explicitly
	// deviates from the original ActivityPub specification.
	Block func(context.Context, vocab.ActivityStreamsBlock) error
	// contains filtered or unexported fields
}

FederatingWrappedCallbacks lists the callback functions that already have some side effect behavior provided by the pub library.

These functions are wrapped for the Federating Protocol.

type HandlerFunc

type HandlerFunc func(c context.Context, w http.ResponseWriter, r *http.Request) (isASRequest bool, err error)

HandlerFunc determines whether an incoming HTTP request is an ActivityStreams GET request, and if so attempts to serve ActivityStreams data.

If an error is returned, then the calling function is responsible for writing to the ResponseWriter as part of error handling.

If 'isASRequest' is false and there is no error, then the calling function may continue processing the request, and the HandlerFunc will not have written anything to the ResponseWriter. For example, a webpage may be served instead.

If 'isASRequest' is true and there is no error, then the HandlerFunc successfully served the request and wrote to the ResponseWriter.

Callers are responsible for authorized access to this resource.

func NewActivityStreamsHandler added in v1.0.0

func NewActivityStreamsHandler(db Database, clock Clock) HandlerFunc

NewActivityStreamsHandler creates a HandlerFunc to serve ActivityStreams requests which are coming from other clients or servers that wish to obtain an ActivityStreams representation of data.

Strips retrieved ActivityStreams values of sensitive fields ('bto' and 'bcc') before responding with them. Sets the appropriate HTTP status code for Tombstone Activities as well.

type HttpClient

type HttpClient interface {
	Do(req *http.Request) (*http.Response, error)
}

HttpClient sends http requests, and is an abstraction only needed by the HttpSigTransport. The standard library's Client satisfies this interface.

type HttpSigTransport added in v1.0.0

type HttpSigTransport struct {
	// contains filtered or unexported fields
}

HttpSigTransport makes a dereference call using HTTP signatures to authenticate the request on behalf of a particular actor.

No rate limiting is applied.

Only one request is tried per call.

func NewHttpSigTransport added in v1.0.0

func NewHttpSigTransport(
	client HttpClient,
	appAgent string,
	clock Clock,
	getSigner, postSigner httpsig.Signer,
	pubKeyId string,
	privKey crypto.PrivateKey) *HttpSigTransport

NewHttpSigTransport returns a new Transport.

It sends requests specifically on behalf of a specific actor on this server. The actor's credentials are used to add an HTTP Signature to requests, which requires an actor's private key, a unique identifier for their public key, and an HTTP Signature signing algorithm.

The client lets users issue requests through any HTTP client, including the standard library's HTTP client.

The appAgent uniquely identifies the calling application's requests, so peers may aid debugging the requests incoming from this server. Note that the agent string will also include one for go-fed, so at minimum peer servers can reach out to the go-fed library to aid in notifying implementors of malformed or unsupported requests.

func (HttpSigTransport) BatchDeliver added in v1.0.0

func (h HttpSigTransport) BatchDeliver(c context.Context, b []byte, recipients []*url.URL) error

BatchDeliver sends concurrent POST requests. Returns an error if any of the requests had an error.

func (HttpSigTransport) Deliver added in v1.0.0

func (h HttpSigTransport) Deliver(c context.Context, b []byte, to *url.URL) error

Deliver sends a POST request with an HTTP Signature.

func (HttpSigTransport) Dereference added in v1.0.0

func (h HttpSigTransport) Dereference(c context.Context, iri *url.URL) ([]byte, error)

Dereference sends a GET request signed with an HTTP Signature to obtain an ActivityStreams value.

type IdProperty added in v1.0.0

type IdProperty interface {
	// GetIRI returns the IRI of this property. When IsIRI returns false,
	// GetIRI will return an arbitrary value.
	GetIRI() *url.URL
	// GetType returns the value in this property as a Type. Returns nil if
	// the value is not an ActivityStreams type, such as an IRI or another
	// value.
	GetType() vocab.Type
	// IsIRI returns true if this property is an IRI.
	IsIRI() bool
}

IdProperty is a property that can readily have its id obtained

type OnFollowBehavior added in v1.0.0

type OnFollowBehavior int

OnFollowBehavior enumerates the different default actions that the go-fed library can provide when receiving a Follow Activity from a peer.

const (
	// OnFollowDoNothing does not take any action when a Follow Activity
	// is received.
	OnFollowDoNothing OnFollowBehavior = iota
	// OnFollowAutomaticallyAccept triggers the side effect of sending an
	// Accept of this Follow request in response.
	OnFollowAutomaticallyAccept
	// OnFollowAutomaticallyAccept triggers the side effect of sending a
	// Reject of this Follow request in response.
	OnFollowAutomaticallyReject
)

type SocialProtocol added in v1.0.0

type SocialProtocol interface {
	// Hook callback after parsing the request body for a client request
	// to the Actor's outbox.
	//
	// Can be used to set contextual information based on the
	// ActivityStreams object received.
	//
	// Only called if the Social API is enabled.
	//
	// Warning: Neither authentication nor authorization has taken place at
	// this time. Doing anything beyond setting contextual information is
	// strongly discouraged.
	//
	// If an error is returned, it is passed back to the caller of
	// PostOutbox. In this case, the DelegateActor implementation must not
	// write a response to the ResponseWriter as is expected that the caller
	// to PostOutbox will do so when handling the error.
	PostOutboxRequestBodyHook(c context.Context, r *http.Request, data vocab.Type) (context.Context, error)
	// AuthenticatePostOutbox delegates the authentication of a POST to an
	// outbox.
	//
	// Only called if the Social API is enabled.
	//
	// If an error is returned, it is passed back to the caller of
	// PostOutbox. In this case, the implementation must not write a
	// response to the ResponseWriter as is expected that the client will
	// do so when handling the error. The 'authenticated' is ignored.
	//
	// If no error is returned, but authentication or authorization fails,
	// then authenticated must be false and error nil. It is expected that
	// the implementation handles writing to the ResponseWriter in this
	// case.
	//
	// Finally, if the authentication and authorization succeeds, then
	// authenticated must be true and error nil. The request will continue
	// to be processed.
	AuthenticatePostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (out context.Context, authenticated bool, err error)
	// SocialCallbacks returns the application logic that handles
	// ActivityStreams received from C2S clients.
	//
	// Note that certain types of callbacks will be 'wrapped' with default
	// behaviors supported natively by the library. Other callbacks
	// compatible with streams.TypeResolver can be specified by 'other'.
	//
	// For example, setting the 'Create' field in the SocialWrappedCallbacks
	// lets an application dependency inject additional behaviors they want
	// to take place, including the default behavior supplied by this
	// library. This is guaranteed to be compliant with the ActivityPub
	// Social protocol.
	//
	// To override the default behavior, instead supply the function in
	// 'other', which does not guarantee the application will be compliant
	// with the ActivityPub Social Protocol.
	//
	// Applications are not expected to handle every single ActivityStreams
	// type and extension. The unhandled ones are passed to DefaultCallback.
	SocialCallbacks(c context.Context) (wrapped SocialWrappedCallbacks, other []interface{}, err error)
	// DefaultCallback is called for types that go-fed can deserialize but
	// are not handled by the application's callbacks returned in the
	// Callbacks method.
	//
	// Applications are not expected to handle every single ActivityStreams
	// type and extension, so the unhandled ones are passed to
	// DefaultCallback.
	DefaultCallback(c context.Context, activity Activity) error
}

SocialProtocol contains behaviors an application needs to satisfy for the full ActivityPub C2S implementation to be supported by this library.

It is only required if the client application wants to support the client-to- server, or social, protocol.

It is passed to the library as a dependency injection from the client application.

type SocialWrappedCallbacks added in v1.0.0

type SocialWrappedCallbacks struct {
	// Create handles additional side effects for the Create ActivityStreams
	// type.
	//
	// The wrapping callback copies the actor(s) to the 'attributedTo'
	// property and copies recipients between the Create activity and all
	// objects. It then saves the entry in the database.
	Create func(context.Context, vocab.ActivityStreamsCreate) error
	// Update handles additional side effects for the Update ActivityStreams
	// type.
	//
	// The wrapping callback applies new top-level values on an object to
	// the stored objects. Any top-level null literals will be deleted on
	// the stored objects as well.
	Update func(context.Context, vocab.ActivityStreamsUpdate) error
	// Delete handles additional side effects for the Delete ActivityStreams
	// type.
	//
	// The wrapping callback replaces the object(s) with tombstones in the
	// database.
	Delete func(context.Context, vocab.ActivityStreamsDelete) error
	// Follow handles additional side effects for the Follow ActivityStreams
	// type.
	//
	// The wrapping callback only ensures the 'Follow' has at least one
	// 'object' entry, but otherwise has no default side effect.
	Follow func(context.Context, vocab.ActivityStreamsFollow) error
	// Add handles additional side effects for the Add ActivityStreams
	// type.
	//
	//
	// The wrapping function will add the 'object' IRIs to a specific
	// 'target' collection if the 'target' collection(s) live on this
	// server.
	Add func(context.Context, vocab.ActivityStreamsAdd) error
	// Remove handles additional side effects for the Remove ActivityStreams
	// type.
	//
	// The wrapping function will remove all 'object' IRIs from a specific
	// 'target' collection if the 'target' collection(s) live on this
	// server.
	Remove func(context.Context, vocab.ActivityStreamsRemove) error
	// Like handles additional side effects for the Like ActivityStreams
	// type.
	//
	// The wrapping function will add the objects on the activity to the
	// "liked" collection of this actor.
	Like func(context.Context, vocab.ActivityStreamsLike) error
	// Undo handles additional side effects for the Undo ActivityStreams
	// type.
	//
	//
	// The wrapping function ensures the 'actor' on the 'Undo'
	// is be the same as the 'actor' on all Activities being undone.
	// It enforces that the actors on the Undo must correspond to all of the
	// 'object' actors in some manner.
	//
	// It is expected that the application will implement the proper
	// reversal of activities that are being undone.
	Undo func(context.Context, vocab.ActivityStreamsUndo) error
	// Block handles additional side effects for the Block ActivityStreams
	// type.
	//
	// The wrapping callback only ensures the 'Block' has at least one
	// 'object' entry, but otherwise has no default side effect. It is up
	// to the wrapped application function to properly enforce the new
	// blocking behavior.
	//
	// Note that go-fed does not federate 'Block' activities received in the
	// Social Protocol.
	Block func(context.Context, vocab.ActivityStreamsBlock) error
	// contains filtered or unexported fields
}

SocialWrappedCallbacks lists the callback functions that already have some side effect behavior provided by the pub library.

These functions are wrapped for the Social Protocol.

type Transport added in v1.0.0

type Transport interface {
	// Dereference fetches the ActivityStreams object located at this IRI
	// with a GET request.
	Dereference(c context.Context, iri *url.URL) ([]byte, error)
	// Deliver sends an ActivityStreams object.
	Deliver(c context.Context, b []byte, to *url.URL) error
	// BatchDeliver sends an ActivityStreams object to multiple recipients.
	BatchDeliver(c context.Context, b []byte, recipients []*url.URL) error
}

Transport makes ActivityStreams calls to other servers in order to send or receive ActivityStreams data.

It is responsible for setting the appropriate request headers, signing the requests if needed, and facilitating the traffic between this server and another.

The transport is exclusively used to issue requests on behalf of an actor, and is never sending requests on behalf of the server in general.

It may be reused multiple times, but never concurrently.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL