Update interface definitions and wrapper improvements.
Wrapping default behavior can now be overridden.
This commit is contained in:
parent
bd8220a56c
commit
cc83b751a1
|
@ -13,6 +13,10 @@ import (
|
||||||
// Protocol), client-to-server (Social API), or both. The Actor represents the
|
// Protocol), client-to-server (Social API), or both. The Actor represents the
|
||||||
// server in either use case.
|
// 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
|
// 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
|
// create them. Refer to the constructor's documentation to determine the exact
|
||||||
// behavior of the Actor on an application.
|
// behavior of the Actor on an application.
|
||||||
|
|
|
@ -124,11 +124,11 @@ func NewActor(c CommonBehavior,
|
||||||
// for the Social Protocol, Federating Protocol, or both.
|
// for the Social Protocol, Federating Protocol, or both.
|
||||||
//
|
//
|
||||||
// It still uses the library as a high-level scaffold, which has the benefit of
|
// It still uses the library as a high-level scaffold, which has the benefit of
|
||||||
// allowing applications to grow into a custom solution without having to
|
// allowing applications to grow into a custom ActivityPub solution without
|
||||||
// refactor the code that passes HTTP requests into the Actor.
|
// having to refactor the code that passes HTTP requests into the Actor.
|
||||||
//
|
//
|
||||||
// It is possible to create a DelegateActor that is not ActivityPub compliant.
|
// It is possible to create a DelegateActor that is not ActivityPub compliant.
|
||||||
// Use with care.
|
// Use with due care.
|
||||||
func NewCustomActor(delegate DelegateActor,
|
func NewCustomActor(delegate DelegateActor,
|
||||||
enableSocialProtocol, enableFederatedProtocol bool,
|
enableSocialProtocol, enableFederatedProtocol bool,
|
||||||
clock Clock) Actor {
|
clock Clock) Actor {
|
||||||
|
|
|
@ -7,6 +7,9 @@ import (
|
||||||
|
|
||||||
// Common contains functions required for both the Social API and Federating
|
// Common contains functions required for both the Social API and Federating
|
||||||
// Protocol.
|
// Protocol.
|
||||||
|
//
|
||||||
|
// It is passed to the library as a dependency injection from the client
|
||||||
|
// application.
|
||||||
type CommonBehavior interface {
|
type CommonBehavior interface {
|
||||||
// AuthenticateGetInbox delegates the authentication of a GET to an
|
// AuthenticateGetInbox delegates the authentication of a GET to an
|
||||||
// inbox.
|
// inbox.
|
||||||
|
|
|
@ -10,14 +10,17 @@ import (
|
||||||
// DelegateActor contains the detailed interface an application must satisfy in
|
// DelegateActor contains the detailed interface an application must satisfy in
|
||||||
// order to implement the ActivityPub specification.
|
// 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
|
// Implementing the DelegateActor requires familiarity with the ActivityPub
|
||||||
// specification, it does not a strong enough abstraction for the client
|
// specification because it does not a strong enough abstraction for the client
|
||||||
// application to ignore the ActivityPub spec. It is very possible to implement
|
// 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
|
// this interface and build a foot-gun that trashes the fediverse without being
|
||||||
// ActivityPub compliant. Please use with due consideration.
|
// ActivityPub compliant. Please use with due consideration.
|
||||||
//
|
//
|
||||||
// Alternatively, build an application that uses the parts of the pub library
|
// Alternatively, build an application that uses the parts of the pub library
|
||||||
// that does not require implementing a DelegateActor so that the ActivityPub
|
// that do not require implementing a DelegateActor so that the ActivityPub
|
||||||
// implementation is completely provided out of the box.
|
// implementation is completely provided out of the box.
|
||||||
type DelegateActor interface {
|
type DelegateActor interface {
|
||||||
// AuthenticatePostInbox delegates the authentication of a POST to an
|
// AuthenticatePostInbox delegates the authentication of a POST to an
|
||||||
|
@ -144,8 +147,8 @@ type DelegateActor interface {
|
||||||
//
|
//
|
||||||
// If an error is returned, it is returned to the caller of PostOutbox.
|
// If an error is returned, it is returned to the caller of PostOutbox.
|
||||||
Deliver(c context.Context, outbox *url.URL, activity Activity) error
|
Deliver(c context.Context, outbox *url.URL, activity Activity) error
|
||||||
// AuthenticatePostOutbox delegates the authentication of a POST to an
|
// AuthenticatePostOutbox delegates the authentication and authorization
|
||||||
// outbox.
|
// of a POST to an outbox.
|
||||||
//
|
//
|
||||||
// Only called if the Social API is enabled.
|
// Only called if the Social API is enabled.
|
||||||
//
|
//
|
||||||
|
|
|
@ -12,6 +12,9 @@ import (
|
||||||
//
|
//
|
||||||
// It is only required if the client application wants to support the server-to-
|
// It is only required if the client application wants to support the server-to-
|
||||||
// server, or federating, protocol.
|
// server, or federating, protocol.
|
||||||
|
//
|
||||||
|
// It is passed to the library as a dependency injection from the client
|
||||||
|
// application.
|
||||||
type FederatingProtocol interface {
|
type FederatingProtocol interface {
|
||||||
// AuthenticatePostInbox delegates the authentication of a POST to an
|
// AuthenticatePostInbox delegates the authentication of a POST to an
|
||||||
// inbox.
|
// inbox.
|
||||||
|
@ -46,12 +49,21 @@ type FederatingProtocol interface {
|
||||||
// to be processed.
|
// to be processed.
|
||||||
Blocked(c context.Context, actorIRIs []*url.URL) (blocked bool, err error)
|
Blocked(c context.Context, actorIRIs []*url.URL) (blocked bool, err error)
|
||||||
// Callbacks returns the application logic that handles ActivityStreams
|
// Callbacks returns the application logic that handles ActivityStreams
|
||||||
// received from federating peers. Note that certain types of callbacks
|
// received from federating peers.
|
||||||
// will be 'wrapped' with default behaviors supported natively by the
|
|
||||||
// library. Other callbacks compatible with streams.TypeResolver can
|
|
||||||
// be specified by 'other'.
|
|
||||||
//
|
//
|
||||||
// Note that the functions in 'wrapped' cannot be provided in 'other'.
|
// 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.
|
||||||
Callbacks(c context.Context) (wrapped FederatingWrappedCallbacks, other []interface{})
|
Callbacks(c context.Context) (wrapped FederatingWrappedCallbacks, other []interface{})
|
||||||
// MaxInboxForwardingRecursionDepth determines how deep to search within
|
// MaxInboxForwardingRecursionDepth determines how deep to search within
|
||||||
// an activity to determine if inbox forwarding needs to occur.
|
// an activity to determine if inbox forwarding needs to occur.
|
||||||
|
|
|
@ -135,63 +135,91 @@ type FederatingWrappedCallbacks struct {
|
||||||
newTransport func(c context.Context, actorBoxIRI *url.URL, gofedAgent string) (t Transport, err error)
|
newTransport func(c context.Context, actorBoxIRI *url.URL, gofedAgent string) (t Transport, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// disjoint ensures that the functions given do not share a type signature with
|
// callbacks returns the WrappedCallbacks members into a single interface slice
|
||||||
// the functions being wrapped in FederatingWrappedCallbacks.
|
// for use in streams.Resolver callbacks.
|
||||||
func (w FederatingWrappedCallbacks) disjoint(fns []interface{}) error {
|
//
|
||||||
// TODO: Instead, if provided in "other" it should override this behavior.
|
// If the given functions have a type that collides with the default behavior,
|
||||||
var s string
|
// then disable our default behavior
|
||||||
|
func (w FederatingWrappedCallbacks) callbacks(fns []interface{}) []interface{} {
|
||||||
|
enableCreate := true
|
||||||
|
enableUpdate := true
|
||||||
|
enableDelete := true
|
||||||
|
enableFollow := true
|
||||||
|
enableAccept := true
|
||||||
|
enableReject := true
|
||||||
|
enableAdd := true
|
||||||
|
enableRemove := true
|
||||||
|
enableLike := true
|
||||||
|
enableAnnounce := true
|
||||||
|
enableUndo := true
|
||||||
|
enableBlock := true
|
||||||
for _, fn := range fns {
|
for _, fn := range fns {
|
||||||
switch fn.(type) {
|
switch fn.(type) {
|
||||||
default:
|
default:
|
||||||
// OK, no collision
|
|
||||||
continue
|
continue
|
||||||
case func(context.Context, vocab.ActivityStreamsCreate) error:
|
case func(context.Context, vocab.ActivityStreamsCreate) error:
|
||||||
s = "Create"
|
enableCreate = false
|
||||||
case func(context.Context, vocab.ActivityStreamsUpdate) error:
|
case func(context.Context, vocab.ActivityStreamsUpdate) error:
|
||||||
s = "Update"
|
enableUpdate = false
|
||||||
case func(context.Context, vocab.ActivityStreamsDelete) error:
|
case func(context.Context, vocab.ActivityStreamsDelete) error:
|
||||||
s = "Delete"
|
enableDelete = false
|
||||||
case func(context.Context, vocab.ActivityStreamsFollow) error:
|
case func(context.Context, vocab.ActivityStreamsFollow) error:
|
||||||
s = "Follow"
|
enableFollow = false
|
||||||
case func(context.Context, vocab.ActivityStreamsAccept) error:
|
case func(context.Context, vocab.ActivityStreamsAccept) error:
|
||||||
s = "Accept"
|
enableAccept = false
|
||||||
case func(context.Context, vocab.ActivityStreamsReject) error:
|
case func(context.Context, vocab.ActivityStreamsReject) error:
|
||||||
s = "Reject"
|
enableReject = false
|
||||||
case func(context.Context, vocab.ActivityStreamsAdd) error:
|
case func(context.Context, vocab.ActivityStreamsAdd) error:
|
||||||
s = "Add"
|
enableAdd = false
|
||||||
case func(context.Context, vocab.ActivityStreamsRemove) error:
|
case func(context.Context, vocab.ActivityStreamsRemove) error:
|
||||||
s = "Remove"
|
enableRemove = false
|
||||||
case func(context.Context, vocab.ActivityStreamsLike) error:
|
case func(context.Context, vocab.ActivityStreamsLike) error:
|
||||||
s = "Like"
|
enableLike = false
|
||||||
case func(context.Context, vocab.ActivityStreamsAnnounce) error:
|
case func(context.Context, vocab.ActivityStreamsAnnounce) error:
|
||||||
s = "Announce"
|
enableAnnounce = false
|
||||||
case func(context.Context, vocab.ActivityStreamsUndo) error:
|
case func(context.Context, vocab.ActivityStreamsUndo) error:
|
||||||
s = "Undo"
|
enableUndo = false
|
||||||
case func(context.Context, vocab.ActivityStreamsBlock) error:
|
case func(context.Context, vocab.ActivityStreamsBlock) error:
|
||||||
s = "Block"
|
enableBlock = false
|
||||||
}
|
}
|
||||||
return fmt.Errorf("callback function handling type %q conflicts with FederatingWrappedCallbacks", s)
|
|
||||||
}
|
}
|
||||||
return nil
|
if enableCreate {
|
||||||
}
|
fns = append(fns, w.create)
|
||||||
|
|
||||||
// callbacks returns the WrappedCallbacks members into a single interface slice
|
|
||||||
// for use in streams.Resolver callbacks.
|
|
||||||
func (w FederatingWrappedCallbacks) callbacks() []interface{} {
|
|
||||||
return []interface{}{
|
|
||||||
w.create,
|
|
||||||
w.update,
|
|
||||||
w.deleteFn,
|
|
||||||
w.follow,
|
|
||||||
w.accept,
|
|
||||||
w.reject,
|
|
||||||
w.add,
|
|
||||||
w.remove,
|
|
||||||
w.like,
|
|
||||||
w.announce,
|
|
||||||
w.undo,
|
|
||||||
w.block,
|
|
||||||
}
|
}
|
||||||
|
if enableUpdate {
|
||||||
|
fns = append(fns, w.update)
|
||||||
|
}
|
||||||
|
if enableDelete {
|
||||||
|
fns = append(fns, w.deleteFn)
|
||||||
|
}
|
||||||
|
if enableFollow {
|
||||||
|
fns = append(fns, w.follow)
|
||||||
|
}
|
||||||
|
if enableAccept {
|
||||||
|
fns = append(fns, w.accept)
|
||||||
|
}
|
||||||
|
if enableReject {
|
||||||
|
fns = append(fns, w.reject)
|
||||||
|
}
|
||||||
|
if enableAdd {
|
||||||
|
fns = append(fns, w.add)
|
||||||
|
}
|
||||||
|
if enableRemove {
|
||||||
|
fns = append(fns, w.remove)
|
||||||
|
}
|
||||||
|
if enableLike {
|
||||||
|
fns = append(fns, w.like)
|
||||||
|
}
|
||||||
|
if enableAnnounce {
|
||||||
|
fns = append(fns, w.announce)
|
||||||
|
}
|
||||||
|
if enableUndo {
|
||||||
|
fns = append(fns, w.undo)
|
||||||
|
}
|
||||||
|
if enableBlock {
|
||||||
|
fns = append(fns, w.block)
|
||||||
|
}
|
||||||
|
return fns
|
||||||
}
|
}
|
||||||
|
|
||||||
// create implements the federating Create activity side effects.
|
// create implements the federating Create activity side effects.
|
||||||
|
|
|
@ -5,12 +5,12 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
// inReplyToer is an ActivityStreams type with a 'inReplyTo' property
|
// inReplyToer is an ActivityStreams type with an 'inReplyTo' property
|
||||||
type inReplyToer interface {
|
type inReplyToer interface {
|
||||||
GetActivityStreamsInReplyTo() vocab.ActivityStreamsInReplyToProperty
|
GetActivityStreamsInReplyTo() vocab.ActivityStreamsInReplyToProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// objecter is an ActivityStreams type with a 'object' property
|
// objecter is an ActivityStreams type with an 'object' property
|
||||||
type objecter interface {
|
type objecter interface {
|
||||||
GetActivityStreamsObject() vocab.ActivityStreamsObjectProperty
|
GetActivityStreamsObject() vocab.ActivityStreamsObjectProperty
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,13 @@ type hrefer interface {
|
||||||
GetActivityStreamsHref() vocab.ActivityStreamsHrefProperty
|
GetActivityStreamsHref() vocab.ActivityStreamsHrefProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// itemser is an ActivityStreams type with a 'items' property
|
// itemser is an ActivityStreams type with an 'items' property
|
||||||
type itemser interface {
|
type itemser interface {
|
||||||
GetActivityStreamsItems() vocab.ActivityStreamsItemsProperty
|
GetActivityStreamsItems() vocab.ActivityStreamsItemsProperty
|
||||||
SetActivityStreamsItems(vocab.ActivityStreamsItemsProperty)
|
SetActivityStreamsItems(vocab.ActivityStreamsItemsProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// orderedItemser is an ActivityStreams type with a 'orderedItems' property
|
// orderedItemser is an ActivityStreams type with an 'orderedItems' property
|
||||||
type orderedItemser interface {
|
type orderedItemser interface {
|
||||||
GetActivityStreamsOrderedItems() vocab.ActivityStreamsOrderedItemsProperty
|
GetActivityStreamsOrderedItems() vocab.ActivityStreamsOrderedItemsProperty
|
||||||
SetActivityStreamsOrderedItems(vocab.ActivityStreamsOrderedItemsProperty)
|
SetActivityStreamsOrderedItems(vocab.ActivityStreamsOrderedItemsProperty)
|
||||||
|
@ -47,7 +47,7 @@ type publisheder interface {
|
||||||
GetActivityStreamsPublished() vocab.ActivityStreamsPublishedProperty
|
GetActivityStreamsPublished() vocab.ActivityStreamsPublishedProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateder is an ActivityStreams type with a 'updateder' property
|
// updateder is an ActivityStreams type with an 'updateder' property
|
||||||
type updateder interface {
|
type updateder interface {
|
||||||
GetActivityStreamsUpdated() vocab.ActivityStreamsUpdatedProperty
|
GetActivityStreamsUpdated() vocab.ActivityStreamsUpdatedProperty
|
||||||
}
|
}
|
||||||
|
@ -76,18 +76,18 @@ type bccer interface {
|
||||||
SetActivityStreamsBcc(i vocab.ActivityStreamsBccProperty)
|
SetActivityStreamsBcc(i vocab.ActivityStreamsBccProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// audiencer is an ActivityStreams type with a 'audience' property
|
// audiencer is an ActivityStreams type with an 'audience' property
|
||||||
type audiencer interface {
|
type audiencer interface {
|
||||||
GetActivityStreamsAudience() vocab.ActivityStreamsAudienceProperty
|
GetActivityStreamsAudience() vocab.ActivityStreamsAudienceProperty
|
||||||
SetActivityStreamsAudience(i vocab.ActivityStreamsAudienceProperty)
|
SetActivityStreamsAudience(i vocab.ActivityStreamsAudienceProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inboxer is an ActivityStreams type with a 'inbox' property
|
// inboxer is an ActivityStreams type with an 'inbox' property
|
||||||
type inboxer interface {
|
type inboxer interface {
|
||||||
GetActivityStreamsInbox() vocab.ActivityStreamsInboxProperty
|
GetActivityStreamsInbox() vocab.ActivityStreamsInboxProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// attributedToer is an ActivityStreams type with a 'attributedTo' property
|
// attributedToer is an ActivityStreams type with an 'attributedTo' property
|
||||||
type attributedToer interface {
|
type attributedToer interface {
|
||||||
GetActivityStreamsAttributedTo() vocab.ActivityStreamsAttributedToProperty
|
GetActivityStreamsAttributedTo() vocab.ActivityStreamsAttributedToProperty
|
||||||
SetActivityStreamsAttributedTo(i vocab.ActivityStreamsAttributedToProperty)
|
SetActivityStreamsAttributedTo(i vocab.ActivityStreamsAttributedToProperty)
|
||||||
|
@ -105,7 +105,7 @@ type shareser interface {
|
||||||
SetActivityStreamsShares(i vocab.ActivityStreamsSharesProperty)
|
SetActivityStreamsShares(i vocab.ActivityStreamsSharesProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// actorer is an ActivityStreams type with a 'actor' property
|
// actorer is an ActivityStreams type with an 'actor' property
|
||||||
type actorer interface {
|
type actorer interface {
|
||||||
GetActivityStreamsActor() vocab.ActivityStreamsActorProperty
|
GetActivityStreamsActor() vocab.ActivityStreamsActorProperty
|
||||||
SetActivityStreamsActor(i vocab.ActivityStreamsActorProperty)
|
SetActivityStreamsActor(i vocab.ActivityStreamsActorProperty)
|
||||||
|
|
|
@ -102,10 +102,7 @@ func (a *sideEffectActor) PostInbox(c context.Context, inboxIRI *url.URL, activi
|
||||||
wrapped.db = a.db
|
wrapped.db = a.db
|
||||||
wrapped.inboxIRI = inboxIRI
|
wrapped.inboxIRI = inboxIRI
|
||||||
wrapped.newTransport = a.s2s.NewTransport
|
wrapped.newTransport = a.s2s.NewTransport
|
||||||
if err = wrapped.disjoint(other); err != nil {
|
res, err := streams.NewTypeResolver(wrapped.callbacks(other))
|
||||||
return err
|
|
||||||
}
|
|
||||||
res, err := streams.NewTypeResolver(append(wrapped.callbacks(), other...))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -283,10 +280,7 @@ func (a *sideEffectActor) PostOutbox(c context.Context, activity Activity, outbo
|
||||||
wrapped.rawActivity = rawJSON
|
wrapped.rawActivity = rawJSON
|
||||||
wrapped.clock = a.clock
|
wrapped.clock = a.clock
|
||||||
wrapped.deliverable = &deliverable
|
wrapped.deliverable = &deliverable
|
||||||
if e = wrapped.disjoint(other); e != nil {
|
res, err := streams.NewTypeResolver(wrapped.callbacks(other))
|
||||||
return
|
|
||||||
}
|
|
||||||
res, err := streams.NewTypeResolver(append(wrapped.callbacks(), other...))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ import (
|
||||||
//
|
//
|
||||||
// It is only required if the client application wants to support the client-to-
|
// It is only required if the client application wants to support the client-to-
|
||||||
// server, or social, protocol.
|
// server, or social, protocol.
|
||||||
|
//
|
||||||
|
// It is passed to the library as a dependency injection from the client
|
||||||
|
// application.
|
||||||
type SocialProtocol interface {
|
type SocialProtocol interface {
|
||||||
// AuthenticatePostOutbox delegates the authentication of a POST to an
|
// AuthenticatePostOutbox delegates the authentication of a POST to an
|
||||||
// outbox.
|
// outbox.
|
||||||
|
@ -32,12 +35,21 @@ type SocialProtocol interface {
|
||||||
// to be processed.
|
// to be processed.
|
||||||
AuthenticatePostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (shouldReturn bool, err error)
|
AuthenticatePostOutbox(c context.Context, w http.ResponseWriter, r *http.Request) (shouldReturn bool, err error)
|
||||||
// Callbacks returns the application logic that handles ActivityStreams
|
// Callbacks returns the application logic that handles ActivityStreams
|
||||||
// received from C2S clients. Note that certain types of callbacks
|
// received from C2S clients.
|
||||||
// will be 'wrapped' with default behaviors supported natively by the
|
|
||||||
// library. Other callbacks compatible with streams.TypeResolver can
|
|
||||||
// be specified by 'other'.
|
|
||||||
//
|
//
|
||||||
// Note that the functions in 'wrapped' cannot be provided in 'other'.
|
// 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.
|
||||||
Callbacks(c context.Context) (wrapped SocialWrappedCallbacks, other []interface{})
|
Callbacks(c context.Context) (wrapped SocialWrappedCallbacks, other []interface{})
|
||||||
// GetOutbox returns the OrderedCollection inbox of the actor for this
|
// GetOutbox returns the OrderedCollection inbox of the actor for this
|
||||||
// context. It is up to the implementation to provide the correct
|
// context. It is up to the implementation to provide the correct
|
||||||
|
|
|
@ -42,22 +42,35 @@ type SocialWrappedCallbacks struct {
|
||||||
// Add handles additional side effects for the Add ActivityStreams
|
// Add handles additional side effects for the Add ActivityStreams
|
||||||
// type.
|
// type.
|
||||||
//
|
//
|
||||||
// TODO: Describe
|
//
|
||||||
|
// 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
|
Add func(context.Context, vocab.ActivityStreamsAdd) error
|
||||||
// Remove handles additional side effects for the Remove ActivityStreams
|
// Remove handles additional side effects for the Remove ActivityStreams
|
||||||
// type.
|
// type.
|
||||||
//
|
//
|
||||||
// TODO: Describe
|
// 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
|
Remove func(context.Context, vocab.ActivityStreamsRemove) error
|
||||||
// Like handles additional side effects for the Like ActivityStreams
|
// Like handles additional side effects for the Like ActivityStreams
|
||||||
// type.
|
// type.
|
||||||
//
|
//
|
||||||
// TODO: Describe
|
// The wrapping function will add the objects on the activity to the
|
||||||
|
// "liked" collection of this actor.
|
||||||
Like func(context.Context, vocab.ActivityStreamsLike) error
|
Like func(context.Context, vocab.ActivityStreamsLike) error
|
||||||
// Undo handles additional side effects for the Undo ActivityStreams
|
// Undo handles additional side effects for the Undo ActivityStreams
|
||||||
// type.
|
// type.
|
||||||
//
|
//
|
||||||
// TODO: Describe
|
//
|
||||||
|
// 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
|
Undo func(context.Context, vocab.ActivityStreamsUndo) error
|
||||||
// Block handles additional side effects for the Block ActivityStreams
|
// Block handles additional side effects for the Block ActivityStreams
|
||||||
// type.
|
// type.
|
||||||
|
@ -89,53 +102,73 @@ type SocialWrappedCallbacks struct {
|
||||||
deliverable *bool
|
deliverable *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// disjoint ensures that the functions given do not share a type signature with
|
// callbacks returns the WrappedCallbacks members into a single interface slice
|
||||||
// the functions being wrapped in SocialWrappedCallbacks.
|
// for use in streams.Resolver callbacks.
|
||||||
func (w SocialWrappedCallbacks) disjoint(fns []interface{}) error {
|
//
|
||||||
var s string
|
// If the given functions have a type that collides with the default behavior,
|
||||||
|
// then disable our default behavior
|
||||||
|
func (w SocialWrappedCallbacks) callbacks(fns []interface{}) []interface{} {
|
||||||
|
enableCreate := true
|
||||||
|
enableUpdate := true
|
||||||
|
enableDelete := true
|
||||||
|
enableFollow := true
|
||||||
|
enableAdd := true
|
||||||
|
enableRemove := true
|
||||||
|
enableLike := true
|
||||||
|
enableUndo := true
|
||||||
|
enableBlock := true
|
||||||
for _, fn := range fns {
|
for _, fn := range fns {
|
||||||
switch fn.(type) {
|
switch fn.(type) {
|
||||||
default:
|
default:
|
||||||
// OK, no collision
|
|
||||||
continue
|
continue
|
||||||
case func(context.Context, vocab.ActivityStreamsCreate) error:
|
case func(context.Context, vocab.ActivityStreamsCreate) error:
|
||||||
s = "Create"
|
enableCreate = false
|
||||||
case func(context.Context, vocab.ActivityStreamsUpdate) error:
|
case func(context.Context, vocab.ActivityStreamsUpdate) error:
|
||||||
s = "Update"
|
enableUpdate = false
|
||||||
case func(context.Context, vocab.ActivityStreamsDelete) error:
|
case func(context.Context, vocab.ActivityStreamsDelete) error:
|
||||||
s = "Delete"
|
enableDelete = false
|
||||||
case func(context.Context, vocab.ActivityStreamsFollow) error:
|
case func(context.Context, vocab.ActivityStreamsFollow) error:
|
||||||
s = "Follow"
|
enableFollow = false
|
||||||
case func(context.Context, vocab.ActivityStreamsAdd) error:
|
case func(context.Context, vocab.ActivityStreamsAdd) error:
|
||||||
s = "Add"
|
enableAdd = false
|
||||||
case func(context.Context, vocab.ActivityStreamsRemove) error:
|
case func(context.Context, vocab.ActivityStreamsRemove) error:
|
||||||
s = "Remove"
|
enableRemove = false
|
||||||
case func(context.Context, vocab.ActivityStreamsLike) error:
|
case func(context.Context, vocab.ActivityStreamsLike) error:
|
||||||
s = "Like"
|
enableLike = false
|
||||||
case func(context.Context, vocab.ActivityStreamsUndo) error:
|
case func(context.Context, vocab.ActivityStreamsUndo) error:
|
||||||
s = "Undo"
|
enableUndo = false
|
||||||
case func(context.Context, vocab.ActivityStreamsBlock) error:
|
case func(context.Context, vocab.ActivityStreamsBlock) error:
|
||||||
s = "Block"
|
enableBlock = false
|
||||||
}
|
}
|
||||||
return fmt.Errorf("callback function handling type %q conflicts with SocialWrappedCallbacks", s)
|
|
||||||
}
|
}
|
||||||
return nil
|
if enableCreate {
|
||||||
}
|
fns = append(fns, w.create)
|
||||||
|
|
||||||
// callbacks returns the WrappedCallbacks members into a single interface slice
|
|
||||||
// for use in streams.Resolver callbacks.
|
|
||||||
func (w SocialWrappedCallbacks) callbacks() []interface{} {
|
|
||||||
return []interface{}{
|
|
||||||
w.create,
|
|
||||||
w.update,
|
|
||||||
w.deleteFn,
|
|
||||||
w.follow,
|
|
||||||
w.add,
|
|
||||||
w.remove,
|
|
||||||
w.like,
|
|
||||||
w.undo,
|
|
||||||
w.block,
|
|
||||||
}
|
}
|
||||||
|
if enableUpdate {
|
||||||
|
fns = append(fns, w.update)
|
||||||
|
}
|
||||||
|
if enableDelete {
|
||||||
|
fns = append(fns, w.deleteFn)
|
||||||
|
}
|
||||||
|
if enableFollow {
|
||||||
|
fns = append(fns, w.follow)
|
||||||
|
}
|
||||||
|
if enableAdd {
|
||||||
|
fns = append(fns, w.add)
|
||||||
|
}
|
||||||
|
if enableRemove {
|
||||||
|
fns = append(fns, w.remove)
|
||||||
|
}
|
||||||
|
if enableLike {
|
||||||
|
fns = append(fns, w.like)
|
||||||
|
}
|
||||||
|
if enableUndo {
|
||||||
|
fns = append(fns, w.undo)
|
||||||
|
}
|
||||||
|
if enableBlock {
|
||||||
|
fns = append(fns, w.block)
|
||||||
|
}
|
||||||
|
return fns
|
||||||
}
|
}
|
||||||
|
|
||||||
// create implements the social Create activity side effects.
|
// create implements the social Create activity side effects.
|
||||||
|
|
|
@ -19,8 +19,15 @@ const (
|
||||||
acceptHeaderValue = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
|
acceptHeaderValue = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
|
||||||
)
|
)
|
||||||
|
|
||||||
// Transport makes ActivityStreams calls to other servers in order to POST or
|
// Transport makes ActivityStreams calls to other servers in order to send or
|
||||||
// GET ActivityStreams data.
|
// 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.
|
// It may be reused multiple times, but never concurrently.
|
||||||
type Transport interface {
|
type Transport interface {
|
||||||
|
@ -52,10 +59,24 @@ type HttpSigTransport struct {
|
||||||
privKey crypto.PrivateKey
|
privKey crypto.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHttpSigTransport returns a new 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 NewHttpSigTransport(
|
func NewHttpSigTransport(
|
||||||
client HttpClient,
|
client HttpClient,
|
||||||
appAgent, gofedAgent string,
|
appAgent string,
|
||||||
clock Clock,
|
clock Clock,
|
||||||
signer httpsig.Signer,
|
signer httpsig.Signer,
|
||||||
pubKeyId string,
|
pubKeyId string,
|
||||||
|
@ -63,7 +84,7 @@ func NewHttpSigTransport(
|
||||||
return &HttpSigTransport{
|
return &HttpSigTransport{
|
||||||
client: client,
|
client: client,
|
||||||
appAgent: appAgent,
|
appAgent: appAgent,
|
||||||
gofedAgent: gofedAgent,
|
gofedAgent: goFedUserAgent(),
|
||||||
clock: clock,
|
clock: clock,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
pubKeyId: pubKeyId,
|
pubKeyId: pubKeyId,
|
||||||
|
@ -71,7 +92,8 @@ func NewHttpSigTransport(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dereferences with a request signed with an HTTP Signature.
|
// Dereference sends a GET request signed with an HTTP Signature to obtain an
|
||||||
|
// ActivityStreams value.
|
||||||
func (h HttpSigTransport) Dereference(c context.Context, iri *url.URL) ([]byte, error) {
|
func (h HttpSigTransport) Dereference(c context.Context, iri *url.URL) ([]byte, error) {
|
||||||
req, err := http.NewRequest("GET", iri.String(), nil)
|
req, err := http.NewRequest("GET", iri.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue